522 lines
24 KiB
Vue
522 lines
24 KiB
Vue
<template>
|
||
<el-drawer
|
||
:title="`接口管理 - ${platformName}`"
|
||
:visible.sync="visible"
|
||
direction="rtl"
|
||
size="78%"
|
||
:before-close="handleClose"
|
||
append-to-body
|
||
>
|
||
<div class="interface-drawer-content">
|
||
<!-- 接口列表 -->
|
||
<div v-show="!editing" class="interface-list">
|
||
<el-row :gutter="10" style="margin-bottom:12px">
|
||
<el-col :span="1.5">
|
||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增接口</el-button>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-table v-loading="loading" :data="list" size="small" border>
|
||
<el-table-column label="排序" prop="sortOrder" width="60" align="center" />
|
||
<el-table-column label="接口名称" prop="name" min-width="140" />
|
||
<el-table-column label="标识" prop="code" width="160" show-overflow-tooltip />
|
||
<el-table-column label="方法" prop="method" width="80" align="center">
|
||
<template slot-scope="scope">
|
||
<el-tag size="mini" :type="methodTagType(scope.row.method)">{{ scope.row.method }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="路径" prop="path" min-width="220" show-overflow-tooltip />
|
||
<el-table-column label="Content-Type" prop="contentType" width="180" show-overflow-tooltip />
|
||
<el-table-column label="入参数量" width="90" align="center">
|
||
<template slot-scope="scope">{{ schemaCount(scope.row.requestSchema) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="text" icon="el-icon-delete" style="color:#f56c6c" @click="handleDelete(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<!-- 编辑表单 -->
|
||
<div v-show="editing" class="interface-edit">
|
||
<div class="edit-header">
|
||
<el-button size="mini" icon="el-icon-back" @click="cancelEdit">返回列表</el-button>
|
||
<span class="edit-title">{{ editTitle }}</span>
|
||
</div>
|
||
|
||
<el-form ref="ifaceForm" :model="form" :rules="rules" label-width="100px" style="margin-top:16px">
|
||
<el-row :gutter="16">
|
||
<el-col :span="12">
|
||
<el-form-item label="接口名称" prop="name">
|
||
<el-input v-model="form.name" placeholder="如:推送倾角数据" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="接口标识" prop="code">
|
||
<el-input v-model="form.code" placeholder="如:dcp_push_inclino" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="16">
|
||
<el-col :span="8">
|
||
<el-form-item label="请求方法" prop="method">
|
||
<el-select v-model="form.method" style="width:100%">
|
||
<el-option v-for="m in methods" :key="m" :label="m" :value="m" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="16">
|
||
<el-form-item label="路径" prop="path">
|
||
<el-input v-model="form.path" placeholder="/api/app/inclino-data/many,支持 {变量名} 路径参数" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="16">
|
||
<el-col :span="8">
|
||
<el-form-item label="Content-Type">
|
||
<el-select v-model="form.contentType" style="width:100%" clearable>
|
||
<el-option label="application/json" value="application/json" />
|
||
<el-option label="application/x-www-form-urlencoded" value="application/x-www-form-urlencoded" />
|
||
<el-option label="multipart/form-data" value="multipart/form-data" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="排序">
|
||
<el-input-number v-model="form.sortOrder" :min="0" :max="999" style="width:100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="备注">
|
||
<el-input v-model="form.remark" placeholder="接口用途说明" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 入参 Schema 可视化表格 -->
|
||
<el-divider content-position="left">入参定义(request_schema)</el-divider>
|
||
<div class="schema-tip">
|
||
定义接口需要的入参字段。参数来源使用业务化名称:
|
||
固定值、认证参数、平台参数、上一步结果、当前设备、自动UUID、子设备传感器列表、基准点成对传感器列表、设备物模型、上报时间。
|
||
</div>
|
||
<el-table :data="requestSchemaRows" size="mini" border style="width:100%;margin-top:8px">
|
||
<el-table-column label="字段名" width="130">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.name" size="mini" placeholder="如 deviceId" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="类型" width="110">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.type" size="mini" style="width:100%">
|
||
<el-option label="string" value="string" />
|
||
<el-option label="number" value="number" />
|
||
<el-option label="boolean" value="boolean" />
|
||
<el-option label="object" value="object" />
|
||
<el-option label="array" value="array" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="参数来源" width="150">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.source" size="mini" style="width:100%" @change="onSourceChange(scope.row)">
|
||
<el-option label="固定值" value="fixed" />
|
||
<el-option label="认证参数" value="auth" />
|
||
<el-option label="平台参数" value="extra" />
|
||
<el-option label="上一步结果" value="context" />
|
||
<el-option label="当前设备" value="device" />
|
||
<el-option label="自动UUID" value="uuid" />
|
||
<el-option label="子设备传感器列表" value="subDeviceSensorIds" />
|
||
<el-option label="基准点成对传感器列表" value="referenceSubDeviceSensorIdPairs" />
|
||
<el-option label="设备物模型" value="thingsModel" />
|
||
<el-option label="上报时间" value="ts" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="取值配置" min-width="180">
|
||
<template slot-scope="scope">
|
||
<!-- fixed: 直接填值 -->
|
||
<el-input v-if="scope.row.source === 'fixed'" v-model="scope.row.value" size="mini" placeholder="固定值" />
|
||
<!-- auth: 选择认证配置中的字段 -->
|
||
<el-select v-else-if="scope.row.source === 'auth' && authFieldOptions.length > 0" v-model="scope.row.field" size="mini" filterable allow-create default-first-option style="width:100%">
|
||
<el-option v-for="item in authFieldOptions" :key="item" :label="item" :value="item" />
|
||
</el-select>
|
||
<el-input v-else-if="scope.row.source === 'auth'" v-model="scope.row.field" size="mini" placeholder="认证参数名,如 userName" />
|
||
<!-- extra: 选择平台参数中的字段 -->
|
||
<el-select v-else-if="scope.row.source === 'extra' && extraFieldOptions.length > 0" v-model="scope.row.field" size="mini" filterable allow-create default-first-option style="width:100%">
|
||
<el-option v-for="item in extraFieldOptions" :key="item" :label="item" :value="item" />
|
||
</el-select>
|
||
<el-input v-else-if="scope.row.source === 'extra'" v-model="scope.row.field" size="mini" placeholder="平台参数名,如 projectId" />
|
||
<!-- context: 上一步结果的key -->
|
||
<el-input v-else-if="scope.row.source === 'context'" v-model="scope.row.contextKey" size="mini" placeholder="流程页可选择,如 step1.id" />
|
||
<!-- device: 设备字段 -->
|
||
<el-select v-else-if="scope.row.source === 'device'" v-model="scope.row.field" size="mini" style="width:100%">
|
||
<el-option label="平台设备ID" value="platform_device_id" />
|
||
<el-option label="平台测点ID" value="platform_point_id" />
|
||
<el-option label="系统设备编号" value="serial_number" />
|
||
</el-select>
|
||
<span v-else-if="scope.row.source === 'uuid'" class="schema-hint">每次请求自动生成UUID</span>
|
||
<span v-else-if="scope.row.source === 'subDeviceSensorIds'" class="schema-hint">自动取设备绑定页子设备映射中的 sensorId 列表</span>
|
||
<span v-else-if="scope.row.source === 'referenceSubDeviceSensorIdPairs'" class="schema-hint">按基准点与每个监测点成对拆分请求</span>
|
||
<span v-else-if="scope.row.source === 'thingsModel'" class="schema-hint">设备绑定页面选择物模型字段</span>
|
||
<span v-else-if="scope.row.source === 'ts'" class="schema-hint">系统自动取设备上报时间</span>
|
||
<span v-else class="schema-hint">请先选择来源</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="必填" width="55" align="center">
|
||
<template slot-scope="scope">
|
||
<el-checkbox v-model="scope.row.required" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="说明" width="140">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.desc" size="mini" placeholder="字段说明" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="数组项定义" width="100" align="center">
|
||
<template slot-scope="scope">
|
||
<el-button v-if="scope.row.type === 'array'" size="mini" type="text" icon="el-icon-s-operation" @click="openItemSchemaDialog(scope.row)">数组项</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="80" align="center">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" type="text" icon="el-icon-delete" style="color:#f56c6c" @click="requestSchemaRows.splice(scope.$index, 1)" />
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<el-button size="mini" icon="el-icon-plus" style="margin-top:8px" @click="addRequestField">添加入参字段</el-button>
|
||
|
||
<!-- 数组项 itemSchema 编辑弹窗 -->
|
||
<el-dialog :visible.sync="itemSchemaDialogVisible" title="定义数组项字段" width="650px" append-to-body :close-on-click-modal="false">
|
||
<div class="schema-tip" style="margin-bottom:8px">
|
||
定义数组中每个元素的字段。可选来源:设备物模型、子设备映射、上报时间、固定值。
|
||
</div>
|
||
<el-table :data="itemSchemaRows" size="mini" border style="width:100%">
|
||
<el-table-column label="字段名" width="130">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.name" size="mini" placeholder="如 height" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="类型" width="100">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.type" size="mini" style="width:100%">
|
||
<el-option label="string" value="string" />
|
||
<el-option label="number" value="number" />
|
||
<el-option label="boolean" value="boolean" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="参数来源" width="150">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.source" size="mini" style="width:100%">
|
||
<el-option label="设备物模型" value="thingsModel" />
|
||
<el-option label="子设备映射" value="subDeviceId" />
|
||
<el-option label="上报时间" value="ts" />
|
||
<el-option label="固定值" value="fixed" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="固定值" width="120">
|
||
<template slot-scope="scope">
|
||
<el-input v-if="scope.row.source === 'fixed'" v-model="scope.row.value" size="mini" placeholder="固定值" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="说明" width="120">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.desc" size="mini" placeholder="说明" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="50" align="center">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" type="text" icon="el-icon-delete" style="color:#f56c6c" @click="itemSchemaRows.splice(scope.$index, 1)" />
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<el-button size="mini" icon="el-icon-plus" style="margin-top:8px" @click="addItemSchemaField">添加字段</el-button>
|
||
<div slot="footer">
|
||
<el-button @click="itemSchemaDialogVisible = false">关闭</el-button>
|
||
<el-button type="primary" @click="confirmItemSchema">确定</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<!-- 出参 Schema 可视化表格 -->
|
||
<el-divider content-position="left">出参定义(response_schema)</el-divider>
|
||
<div class="schema-tip">
|
||
定义接口响应中需要提取的字段。<b>path</b> 为 JSON 路径(如 access_token、[0].id)
|
||
</div>
|
||
<el-table :data="responseSchemaRows" size="mini" border style="width:100%;margin-top:8px">
|
||
<el-table-column label="字段名" width="140">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.name" size="mini" placeholder="如 access_token" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="类型" width="110">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.type" size="mini" style="width:100%">
|
||
<el-option label="string" value="string" />
|
||
<el-option label="number" value="number" />
|
||
<el-option label="boolean" value="boolean" />
|
||
<el-option label="object" value="object" />
|
||
<el-option label="array" value="array" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="JSON路径(path)" min-width="180">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.path" size="mini" placeholder="如 access_token 或 [0].id" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="说明" min-width="140">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.desc" size="mini" placeholder="字段说明" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="50" align="center">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" type="text" icon="el-icon-delete" style="color:#f56c6c" @click="responseSchemaRows.splice(scope.$index, 1)" />
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<el-button size="mini" icon="el-icon-plus" style="margin-top:8px" @click="addResponseField">添加出参字段</el-button>
|
||
</el-form>
|
||
|
||
<div class="edit-footer">
|
||
<el-button @click="cancelEdit">取消</el-button>
|
||
<el-button type="primary" @click="submitForm" :loading="submitLoading">保存</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-drawer>
|
||
</template>
|
||
|
||
<script>
|
||
import { listPlatformInterface, addPlatformInterface, updatePlatformInterface, delPlatformInterface } from '@/api/platform/interface'
|
||
import { getPlatformInstance } from '@/api/platform/instance'
|
||
|
||
export default {
|
||
name: 'PlatformInterfaceDrawer',
|
||
props: {
|
||
platformId: { type: Number, default: null },
|
||
platformName: { type: String, default: '' }
|
||
},
|
||
data() {
|
||
return {
|
||
visible: false,
|
||
loading: false,
|
||
submitLoading: false,
|
||
list: [],
|
||
editing: false,
|
||
editTitle: '新增接口',
|
||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
||
form: {},
|
||
authFieldOptions: [],
|
||
extraFieldOptions: [],
|
||
requestSchemaRows: [],
|
||
responseSchemaRows: [],
|
||
itemSchemaDialogVisible: false,
|
||
itemSchemaEditingRow: null,
|
||
itemSchemaRows: [],
|
||
rules: {
|
||
name: [{ required: true, message: '请输入接口名称', trigger: 'blur' }],
|
||
code: [{ required: true, message: '请输入接口标识', trigger: 'blur' }],
|
||
method: [{ required: true, message: '请选择请求方法', trigger: 'change' }],
|
||
path: [{ required: true, message: '请输入接口路径', trigger: 'blur' }]
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
open() {
|
||
this.visible = true
|
||
this.editing = false
|
||
this.loadPlatformOptions()
|
||
this.getList()
|
||
},
|
||
handleClose(done) {
|
||
this.editing = false
|
||
done()
|
||
},
|
||
getList() {
|
||
if (!this.platformId) return
|
||
this.loading = true
|
||
listPlatformInterface({ platformId: this.platformId, pageNum: 1, pageSize: 200 }).then(res => {
|
||
this.list = res.rows || []
|
||
this.loading = false
|
||
})
|
||
},
|
||
schemaCount(schema) {
|
||
if (!schema) return 0
|
||
try { return JSON.parse(schema).length } catch (e) { return 0 }
|
||
},
|
||
methodTagType(method) {
|
||
const map = { GET: '', POST: 'success', PUT: 'warning', DELETE: 'danger', PATCH: 'info' }
|
||
return map[method] || ''
|
||
},
|
||
handleAdd() {
|
||
this.form = {
|
||
platformId: this.platformId,
|
||
method: 'POST',
|
||
path: '',
|
||
contentType: 'application/json',
|
||
sortOrder: this.list.length + 1,
|
||
remark: ''
|
||
}
|
||
this.requestSchemaRows = []
|
||
this.responseSchemaRows = []
|
||
this.editTitle = '新增接口'
|
||
this.editing = true
|
||
},
|
||
handleEdit(row) {
|
||
this.form = { ...row }
|
||
// 解析 requestSchema JSON → 表格行
|
||
this.requestSchemaRows = this.parseSchema(row.requestSchema)
|
||
this.responseSchemaRows = this.parseSchema(row.responseSchema)
|
||
this.editTitle = '编辑接口 - ' + row.name
|
||
this.editing = true
|
||
},
|
||
parseSchema(json) {
|
||
if (!json) return []
|
||
try {
|
||
const arr = JSON.parse(json)
|
||
return arr.map(f => ({ ...f, itemSchema: f.itemSchema || [], required: !!f.required }))
|
||
} catch (e) { return [] }
|
||
},
|
||
handleDelete(row) {
|
||
this.$confirm(`确认删除接口【${row.name}】?`).then(() => {
|
||
delPlatformInterface(row.id).then(() => {
|
||
this.$modal.msgSuccess('删除成功')
|
||
this.getList()
|
||
})
|
||
})
|
||
},
|
||
cancelEdit() {
|
||
this.editing = false
|
||
},
|
||
onSourceChange(row) {
|
||
// 切换 source 时清空无关字段
|
||
row.value = undefined
|
||
row.field = undefined
|
||
row.contextKey = undefined
|
||
},
|
||
loadPlatformOptions() {
|
||
if (!this.platformId) {
|
||
this.authFieldOptions = []
|
||
this.extraFieldOptions = []
|
||
return
|
||
}
|
||
getPlatformInstance(this.platformId).then(res => {
|
||
const data = res.data || {}
|
||
this.authFieldOptions = this.extractJsonKeys(data.authConfig)
|
||
this.extraFieldOptions = this.extractJsonKeys(data.extraConfig)
|
||
}).catch(() => {
|
||
this.authFieldOptions = []
|
||
this.extraFieldOptions = []
|
||
})
|
||
},
|
||
extractJsonKeys(value) {
|
||
if (!value) return []
|
||
try {
|
||
return Object.keys(JSON.parse(value))
|
||
} catch (e) {
|
||
return []
|
||
}
|
||
},
|
||
addRequestField() {
|
||
this.requestSchemaRows.push({ name: '', type: 'string', source: 'fixed', value: '', field: '', contextKey: '', required: false, desc: '', itemSchema: [] })
|
||
},
|
||
addResponseField() {
|
||
this.responseSchemaRows.push({ name: '', type: 'string', path: '', desc: '' })
|
||
},
|
||
openItemSchemaDialog(row) {
|
||
this.itemSchemaEditingRow = row
|
||
this.itemSchemaRows = (row.itemSchema || []).map(s => ({ ...s }))
|
||
if (this.itemSchemaRows.length === 0) {
|
||
// 预填一个默认字段
|
||
this.itemSchemaRows.push({ name: '', type: 'string', source: 'thingsModel', value: '', desc: '' })
|
||
}
|
||
this.itemSchemaDialogVisible = true
|
||
},
|
||
addItemSchemaField() {
|
||
this.itemSchemaRows.push({ name: '', type: 'string', source: 'thingsModel', value: '', desc: '' })
|
||
},
|
||
confirmItemSchema() {
|
||
if (this.itemSchemaEditingRow) {
|
||
this.itemSchemaEditingRow.itemSchema = this.itemSchemaRows.filter(s => s.name).map(s => {
|
||
const item = { name: s.name, type: s.type || 'string', source: s.source || 'thingsModel', desc: s.desc }
|
||
if (s.source === 'fixed') item.value = s.value
|
||
return Object.assign({}, item)
|
||
})
|
||
}
|
||
this.itemSchemaDialogVisible = false
|
||
},
|
||
submitForm() {
|
||
this.$refs.ifaceForm.validate(valid => {
|
||
if (!valid) return
|
||
// 将表格行序列化为 JSON 存入 form
|
||
this.form.requestSchema = JSON.stringify(this.requestSchemaRows.filter(r => r.name).map(r => {
|
||
const field = { name: r.name, type: r.type, source: r.source, required: !!r.required, desc: r.desc }
|
||
if (r.type === 'array' && r.itemSchema && r.itemSchema.length > 0) {
|
||
field.itemSchema = r.itemSchema.filter(s => s.name).map(s => {
|
||
const item = { name: s.name, type: s.type || 'string', source: s.source || 'thingsModel', desc: s.desc }
|
||
if (s.source === 'fixed') item.value = s.value
|
||
return item
|
||
})
|
||
}
|
||
if (r.source === 'fixed') field.value = r.value
|
||
if (r.source === 'auth' || r.source === 'extra' || r.source === 'device') field.field = r.field
|
||
if (r.source === 'context') field.contextKey = r.contextKey
|
||
return field
|
||
}))
|
||
this.form.responseSchema = JSON.stringify(this.responseSchemaRows.filter(r => r.name).map(r => ({
|
||
name: r.name, type: r.type, path: r.path, desc: r.desc
|
||
})))
|
||
|
||
this.submitLoading = true
|
||
const api = this.form.id ? updatePlatformInterface : addPlatformInterface
|
||
api(this.form).then(() => {
|
||
this.$modal.msgSuccess(this.form.id ? '修改成功' : '新增成功')
|
||
this.editing = false
|
||
this.getList()
|
||
}).finally(() => { this.submitLoading = false })
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.interface-drawer-content {
|
||
padding: 16px 24px;
|
||
height: 100%;
|
||
overflow-y: auto;
|
||
}
|
||
.edit-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding-bottom: 12px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
}
|
||
.edit-title {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
color: #303133;
|
||
}
|
||
.edit-footer {
|
||
margin-top: 20px;
|
||
padding-top: 16px;
|
||
border-top: 1px solid #ebeef5;
|
||
text-align: right;
|
||
}
|
||
.schema-tip {
|
||
font-size: 12px;
|
||
color: #909399;
|
||
line-height: 1.6;
|
||
margin-top: 4px;
|
||
}
|
||
.schema-hint {
|
||
font-size: 12px;
|
||
color: #c0c4cc;
|
||
}
|
||
</style>
|