edit.vue 15 KB

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