edit.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. <template>
  2. <el-dialog
  3. class="api-edit"
  4. v-model="showDialog"
  5. :title="`${formData.sourceId ? '编辑数据源' : '新增数据源'}`"
  6. width="800px"
  7. :close-on-click-modal="false"
  8. :close-on-press-escape="false"
  9. >
  10. <el-form class="inline-form" ref="formRef" :model="formData" :rules="ruleForm" label-width="120px">
  11. <el-form-item label="数据源标识" prop="key">
  12. <el-input v-model="formData.key" placeholder="请输入数据源名称" :disabled="formData.sourceId" />
  13. </el-form-item>
  14. <el-form-item label="数据源名称" prop="name">
  15. <el-input v-model="formData.name" placeholder="请输入数据源名称" />
  16. </el-form-item>
  17. <el-form-item label="描述" prop="desc">
  18. <el-input v-model="formData.desc" type="textarea" placeholder="请输入内容"></el-input>
  19. </el-form-item>
  20. <el-form-item label="数据来源" prop="from" v-if="!formData.sourceId">
  21. <el-radio-group v-model="formData.from">
  22. <el-radio :label="1">api导入</el-radio>
  23. <el-radio :label="4">设备或产品</el-radio>
  24. <el-radio :label="2">数据库</el-radio>
  25. </el-radio-group>
  26. </el-form-item>
  27. <el-divider content-position="left">数据源配置</el-divider>
  28. <div v-if="formData.from == 1">
  29. <el-form-item label="请求方法" prop="config.method">
  30. <el-select v-model="formData.config.method" :rules="ruleForm['config.method']" placeholder="请选择请求方法">
  31. <el-option v-for="item in methodData" :key="item.value" :label="item.label" :value="item.value" />
  32. </el-select>
  33. </el-form-item>
  34. <el-form-item label="请求地址" prop="config.url">
  35. <el-input v-model="formData.config.url" placeholder="请输入请求地址" :rules="ruleForm['config.url']" />
  36. </el-form-item>
  37. <el-form-item label="定时请求" prop="config.cronExpression">
  38. <div style="display: flex">
  39. <el-input v-model="formData.config.cronExpression" placeholder="请输入cron表达式" :rules="ruleForm['config.cronExpression']" />
  40. <el-button type="success" @click="showCron('config')" style="margin-left: 5px">设置</el-button>
  41. </div>
  42. </el-form-item>
  43. <div class="box-content">
  44. <div>
  45. <div
  46. v-for="(item, index) in requestParams"
  47. :key="index"
  48. style="padding: 10px; border: 1px solid #eee; margin-bottom: 10px; position: relative"
  49. >
  50. <div class="conicon" style="width: 100%; text-align: right; position: absolute; right: -8px; top: -8px; color: red">
  51. <el-icon @click="delParams(index)">
  52. <CircleClose />
  53. </el-icon>
  54. </div>
  55. <div style="display: flex">
  56. <el-divider content-position="left">请求参数</el-divider>
  57. </div>
  58. <div class="content-f" v-for="(aaa, bbb) in item" :key="bbb">
  59. <el-select v-model="aaa.type" placeholder="参数类型" style="width: 320px">
  60. <el-option v-for="item in paramData" :key="item.value" :label="item.label" :value="item.value" />
  61. </el-select>
  62. <el-input v-model="aaa.name" placeholder="请输入参数标题" style="width: 320px" />
  63. <el-input v-model="aaa.key" placeholder="请输入参标识" style="width: 320px" />
  64. <el-input v-model="aaa.value" placeholder="请输入参数值" style="width: 320px" />
  65. <div class="conicon">
  66. <el-icon @click="delParamss(index, bbb)">
  67. <Delete />
  68. </el-icon>
  69. </div>
  70. </div>
  71. <el-button type="primary" class="addbutton" @click="addParams(index)">增加</el-button>
  72. <div style=""></div>
  73. </div>
  74. </div>
  75. </div>
  76. <el-button type="success" class="addbutton" @click="addParamss">增加分组</el-button>
  77. </div>
  78. <div v-if="formData.from == 4">
  79. <el-form-item label="设备或产品">
  80. <el-radio-group v-model="deviceOrProduct" @change=";(formData.devconfig.productKey = ''), (formData.devconfig.deviceKey = '')">
  81. <el-radio label="device">设备</el-radio>
  82. <el-radio label="product">产品</el-radio>
  83. </el-radio-group>
  84. </el-form-item>
  85. <el-form-item label="选择设备" v-if="deviceOrProduct == 'device'" prop="devconfig.deviceKey">
  86. <el-select
  87. v-model="formData.devconfig.deviceKey"
  88. :rules="ruleForm['devconfig.deviceKey']"
  89. filterable
  90. placeholder="请选择设备"
  91. @change="formData.devconfig.productKey = ''"
  92. >
  93. <el-option v-for="item in sourceData" :key="item.key" :label="item.name" :value="item.key">
  94. <span style="float: left">{{ item.name }}</span>
  95. <span style="float: right; font-size: 13px">{{ item.key }}</span>
  96. </el-option>
  97. </el-select>
  98. </el-form-item>
  99. <el-form-item label="选择产品" v-if="deviceOrProduct == 'product'" prop="devconfig.productKey">
  100. <el-select
  101. v-model="formData.devconfig.productKey"
  102. :rules="ruleForm['devconfig.productKey']"
  103. filterable
  104. placeholder="请选择产品"
  105. @change="formData.devconfig.deviceKey = ''"
  106. >
  107. <el-option v-for="item in producList" :key="item.key" :label="item.name" :value="item.key">
  108. <span style="float: left">{{ item.name }}</span>
  109. <span style="float: right; font-size: 13px">{{ item.key }}</span>
  110. </el-option>
  111. </el-select>
  112. </el-form-item>
  113. </div>
  114. <div v-if="formData.from == 2">
  115. <el-form-item label="数据来源" prop="tabconfig.type">
  116. <el-radio-group v-model="formData.tabconfig.type" :rules="ruleForm['tabconfig.type']">
  117. <el-radio label="mysql">mysql</el-radio>
  118. <el-radio label="mssql">mssql</el-radio>
  119. </el-radio-group>
  120. </el-form-item>
  121. <div class="inline">
  122. <el-form-item label="主机地址" prop="tabconfig.host">
  123. <el-input v-model="formData.tabconfig.host" placeholder="请输入主机地址" :rules="ruleForm['tabconfig.host']" />
  124. </el-form-item>
  125. <el-form-item label="端口号" prop="tabconfig.port">
  126. <el-input v-model="formData.tabconfig.port" placeholder="请输入端口号" :rules="ruleForm['tabconfig.port']" />
  127. </el-form-item>
  128. </div>
  129. <div class="inline">
  130. <el-form-item label="用户名" prop="tabconfig.user">
  131. <el-input v-model="formData.tabconfig.user" placeholder="请输入用户名" :rules="ruleForm['tabconfig.user']" />
  132. </el-form-item>
  133. <el-form-item label="密码" prop="tabconfig.passwd">
  134. <el-input v-model="formData.tabconfig.passwd" placeholder="请输入密码" :rules="ruleForm['tabconfig.passwd']" />
  135. </el-form-item>
  136. </div>
  137. <el-form-item label="数据库名称" prop="tabconfig.dbName">
  138. <el-input v-model="formData.tabconfig.dbName" placeholder="请输入数据库名称" :rules="ruleForm['tabconfig.dbName']" />
  139. </el-form-item>
  140. <el-form-item label="执行方式" prop="tabconfig.queryType">
  141. <el-radio-group v-model="formData.tabconfig.queryType" :rules="ruleForm['tabconfig.queryType']">
  142. <el-radio label="tableName">数据表</el-radio>
  143. <el-radio label="sql">Sql</el-radio>
  144. </el-radio-group>
  145. </el-form-item>
  146. <el-form-item label="" prop="tabconfig.tableName">
  147. <el-input
  148. v-model="formData.tabconfig.tableName"
  149. type="textarea"
  150. :placeholder="formData.tabconfig.queryType == 'sql' ? '请输入sql语句' : '请输入表名称'"
  151. />
  152. </el-form-item>
  153. <el-form-item label="主键字段" prop="tabconfig.pk">
  154. <el-input v-model="formData.tabconfig.pk" placeholder="请输入主键字段" :rules="ruleForm['tabconfig.pk']" />
  155. </el-form-item>
  156. <el-form-item label="每次获取数量" prop="tabconfig.num">
  157. <el-input v-model="formData.tabconfig.num" placeholder="请输入每次获取数量" :rules="ruleForm['tabconfig.num']" />
  158. </el-form-item>
  159. <el-form-item label="任务表达式" prop="tabconfig.cronExpression">
  160. <div style="display: flex">
  161. <el-input v-model="formData.tabconfig.cronExpression" placeholder="请输入cron任务表达式" :rules="ruleForm['tabconfig.cronExpression']" />
  162. <el-button type="success" @click="showCron('tabconfig')" style="margin-left: 5px">设置</el-button>
  163. </div>
  164. </el-form-item>
  165. </div>
  166. </el-form>
  167. <template #footer>
  168. <div class="dialog-footer">
  169. <el-button @click="onTest" type="warning" v-if="sourceId > 0">测试</el-button>
  170. <el-button @click="showDialog = false">取消</el-button>
  171. <el-button type="primary" @click="onSubmit">确定</el-button>
  172. </div>
  173. </template>
  174. </el-dialog>
  175. <el-dialog v-model="dialogVisible" title="返回Json数据" width="30%">
  176. <JsonViewer :value="jsonData" boxed sort theme="jv-dark" @click="onKeyclick" />
  177. <template #footer>
  178. <span class="dialog-footer">
  179. <el-button @click="dialogVisible = false">关闭</el-button>
  180. </span>
  181. </template>
  182. </el-dialog>
  183. <el-dialog v-model="cronShow" title="选择Cron规则" width="60%">
  184. <vue3cron @handlelisten="handlelisten" :type="crontype" @close="cronclose"></vue3cron>
  185. </el-dialog>
  186. </template>
  187. <script lang="ts" setup>
  188. import { ref, reactive, nextTick } from 'vue'
  189. import api from '/@/api/datahub'
  190. import deviceApi from '/@/api/device'
  191. import { ruleRequired } from '/@/utils/validator'
  192. import 'vue3-json-viewer/dist/index.css'
  193. import vue3cron from '/@/components/vue3cron/vue3cron.vue'
  194. import { ElMessage } from 'element-plus'
  195. import { Delete, CircleClose } from '@element-plus/icons-vue'
  196. const emit = defineEmits(['typeList'])
  197. const showDialog = ref(false)
  198. const deviceOrProduct = ref('device')
  199. const dialogVisible = ref(false)
  200. const cronShow = ref(false)
  201. const formRef = ref()
  202. const jsonData = ref()
  203. const crontype = ref()
  204. const sourceData = ref([])
  205. const producList = ref([])
  206. const sourceId = ref()
  207. const methodData = ref([
  208. {
  209. label: 'GET',
  210. value: 'get',
  211. },
  212. {
  213. label: 'POST',
  214. value: 'post',
  215. },
  216. ])
  217. const paramData = ref([
  218. {
  219. lable: 'header',
  220. value: 'header',
  221. },
  222. {
  223. lable: 'body',
  224. value: 'body',
  225. },
  226. {
  227. lable: 'param',
  228. value: 'param',
  229. },
  230. ])
  231. const requestParams = ref([
  232. [
  233. {
  234. type: '',
  235. key: '',
  236. name: '',
  237. value: '',
  238. },
  239. ],
  240. ])
  241. const delParams = (index: number) => {
  242. requestParams.value.splice(index, 1)
  243. }
  244. const delParamss = (index: number, bbb: number) => {
  245. requestParams.value[index].splice(bbb, 1)
  246. }
  247. const addParamss = () => {
  248. requestParams.value.push([
  249. {
  250. type: '',
  251. key: '',
  252. name: '',
  253. value: '',
  254. },
  255. ])
  256. }
  257. const addParams = (index: number) => {
  258. requestParams.value[index].push({
  259. type: '',
  260. key: '',
  261. name: '',
  262. value: '',
  263. })
  264. }
  265. const handlelisten = (e: any) => {
  266. if (e.type == 'config') {
  267. formData.config.cronExpression = e.cron
  268. } else if (e.type == 'tabconfig') {
  269. formData.tabconfig.cronExpression = e.cron
  270. }
  271. }
  272. const showCron = (type: string) => {
  273. crontype.value = type
  274. cronShow.value = true
  275. }
  276. const cronclose = () => {
  277. cronShow.value = false
  278. }
  279. const onTest = () => {
  280. if (formData.from == 1) {
  281. api.common.api(sourceId.value).then((res: any) => {
  282. jsonData.value = JSON.parse(res.data)
  283. dialogVisible.value = true
  284. })
  285. } else if (formData.from == 4) {
  286. api.common.devapi(sourceId.value).then((res: any) => {
  287. jsonData.value = JSON.parse(res.data)
  288. dialogVisible.value = true
  289. })
  290. }
  291. }
  292. const baseForm = {
  293. sourceId: undefined,
  294. name: '',
  295. key: '',
  296. desc: '',
  297. from: 1,
  298. config: {
  299. method: '',
  300. url: '',
  301. cronExpression: '',
  302. requestParams: [],
  303. },
  304. devconfig: {
  305. deviceKey: '',
  306. productKey: '',
  307. },
  308. tabconfig: {
  309. type: 'mysql',
  310. host: '',
  311. port: '',
  312. user: '',
  313. passwd: '',
  314. dbName: '',
  315. queryType: '',
  316. tableName: '',
  317. pk: '',
  318. num: '',
  319. cronExpression: '',
  320. },
  321. }
  322. const onKeyclick = () => {}
  323. const formData = reactive({
  324. ...baseForm,
  325. })
  326. const ruleForm = {
  327. key: [ruleRequired('数据源标识不能为空')],
  328. name: [ruleRequired('数据源名称不能为空')],
  329. from: [ruleRequired('数据源类型不能为空')],
  330. 'config.method': [
  331. { required: true, message: '请求方法不能为空', trigger: 'change' },
  332. {
  333. validator: (rule: any, value: string, callback: any) => {
  334. if (formData.from === 1 && !formData.config.method) {
  335. callback(new Error('请求方法不能为空'))
  336. } else {
  337. callback()
  338. }
  339. },
  340. trigger: 'change',
  341. },
  342. ],
  343. 'config.url': [ruleRequired('请求地址不能为空')],
  344. 'config.cronExpression': [ruleRequired('定时请求不能为空')],
  345. 'devconfig.deviceKey': [ruleRequired('请选择设备')],
  346. 'devconfig.productKey': [ruleRequired('请选择产品')],
  347. 'tabconfig.type': [ruleRequired('请选择数据来源')],
  348. 'tabconfig.host': [ruleRequired('请输入主机地址')],
  349. 'tabconfig.port': [ruleRequired('请输入端口号')],
  350. 'tabconfig.user': [ruleRequired('请输入用户名')],
  351. 'tabconfig.passwd': [ruleRequired('请输入密码')],
  352. 'tabconfig.dbName': [ruleRequired('请输入数据库名称')],
  353. 'tabconfig.queryType': [ruleRequired('请选择执行方式')],
  354. 'tabconfig.tableName': [ruleRequired('该项不能为空')],
  355. 'tabconfig.pk': [ruleRequired('请输入主键字段')],
  356. 'tabconfig.num': [ruleRequired('请输入每次获取数量')],
  357. 'tabconfig.cronExpression': [ruleRequired('请输入cron任务表达式')],
  358. }
  359. const getDevData = () => {
  360. api.common.getdevList({}).then((res: any) => {
  361. sourceData.value = res.device
  362. })
  363. deviceApi.product.getLists().then((res: any) => {
  364. producList.value = res.product
  365. })
  366. }
  367. const onSubmit = async () => {
  368. await formRef.value.validate()
  369. if (formData.from == 1) {
  370. let form = {
  371. sourceId: sourceId.value ? sourceId.value : '',
  372. key: formData.key,
  373. name: formData.name,
  374. desc: formData.desc,
  375. from: formData.from,
  376. config: {
  377. ...formData.config,
  378. requestParams: requestParams.value,
  379. },
  380. }
  381. const theApi = sourceId.value ? api.common.edit : api.common.add
  382. await theApi(form)
  383. ElMessage.success('操作成功')
  384. resetForm()
  385. showDialog.value = false
  386. emit('typeList')
  387. } else if (formData.from == 4) {
  388. let form = {
  389. sourceId: formData.sourceId ? formData.sourceId : '',
  390. key: formData.key,
  391. name: formData.name,
  392. desc: formData.desc,
  393. from: formData.from,
  394. config: formData.devconfig,
  395. }
  396. const theApi = formData.sourceId ? api.common.devedit : api.common.devadd
  397. await theApi(form)
  398. ElMessage.success('操作成功')
  399. resetForm()
  400. showDialog.value = false
  401. emit('typeList')
  402. } else if (formData.from == 2) {
  403. let form = {
  404. sourceId: formData.sourceId ? formData.sourceId : '',
  405. key: formData.key,
  406. name: formData.name,
  407. desc: formData.desc,
  408. from: formData.from,
  409. config: formData.tabconfig,
  410. }
  411. const theApi = formData.sourceId ? api.common.dbedit : api.common.dbadd
  412. await theApi(form)
  413. ElMessage.success('操作成功')
  414. resetForm()
  415. showDialog.value = false
  416. emit('typeList')
  417. }
  418. }
  419. const resetForm = async () => {
  420. Object.assign(formData, { ...baseForm })
  421. formRef.value && formRef.value.resetFields()
  422. requestParams.value = [
  423. [
  424. {
  425. type: '',
  426. key: '',
  427. name: '',
  428. value: '',
  429. },
  430. ],
  431. ]
  432. }
  433. const openDialog = async (row: any) => {
  434. resetForm()
  435. showDialog.value = true
  436. nextTick(() => {
  437. if (row) {
  438. sourceId.value = row.sourceId
  439. api.common.detail(row.sourceId).then((res: any) => {
  440. Object.assign(formData, { ...res.data })
  441. if (res.data.from == 1) {
  442. formData.config = res.data.apiConfig
  443. requestParams.value = res.data.apiConfig.requestParams
  444. } else if (res.data.from == 4) {
  445. deviceOrProduct.value = res.data.deviceConfig.deviceKey ? 'device' : 'product'
  446. formData.devconfig = res.data.deviceConfig
  447. } else if (res.data.from == 2) {
  448. formData.tabconfig = res.data.dbConfig
  449. }
  450. })
  451. }
  452. getDevData()
  453. })
  454. }
  455. defineExpose({ openDialog })
  456. </script>
  457. <style scoped lang="scss">
  458. .inline {
  459. display: inline-flex;
  460. }
  461. .el-input__wrapper {
  462. width: 98%;
  463. }
  464. .box-content {
  465. border: 1px solid #e8e8e8;
  466. margin: 10px;
  467. padding: 10px;
  468. }
  469. .content-f {
  470. display: flex;
  471. margin-bottom: 10px;
  472. }
  473. .content-f .el-input__wrapper {
  474. margin-right: 5px;
  475. }
  476. .addbutton {
  477. width: 100%;
  478. margin-top: 10px;
  479. background: #fff;
  480. border: 1px solid #d1d1d1;
  481. color: #8d8b8b;
  482. }
  483. .conicon {
  484. width: 55px;
  485. height: 25px;
  486. font-size: 28px;
  487. line-height: 28px;
  488. cursor: pointer;
  489. }
  490. .jv-node {
  491. margin-left: 25px;
  492. }
  493. </style>