index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. <template>
  2. <div class="table-box">
  3. <ProTable ref="proTable" :columns="columns" row-key="id" :request-api="listToInfraredApi">
  4. <!-- 表格 header 按钮 -->
  5. <template #tableHeader="scope">
  6. <el-button type="primary" v-auth="['demo:toInfrared:add']" icon="CirclePlus" @click="openDialog(1, '可见光转红外新增')"> 新增 </el-button>
  7. <!-- <el-button type="primary" v-auth="['demo:toInfrared:import']" icon="Upload" plain @click="batchAdd"> 导入 </el-button>
  8. <el-button type="primary" v-auth="['demo:toInfrared:export']" icon="Download" plain @click="downloadFile"> 导出 </el-button> -->
  9. <el-button
  10. type="danger"
  11. v-auth="['demo:toInfrared:remove']"
  12. icon="Delete"
  13. plain
  14. :disabled="!scope.isSelected"
  15. @click="batchDelete(scope.selectedListIds)"
  16. >
  17. 批量删除
  18. </el-button>
  19. </template>
  20. <!-- 表格操作 -->
  21. <template #operation="scope">
  22. <el-button type="primary" link icon="View" v-if="scope.row.algorithmModelId != null" @click="openModelDialog(scope.row)">
  23. <!--@click="openStartDialog(scope.row)" -->
  24. 详情
  25. </el-button>
  26. <el-button
  27. type="primary"
  28. link
  29. icon="View"
  30. v-auth="['demo:ToInfrared:start']"
  31. v-if="scope.row.status == '0' || scope.row.status == '3' || scope.row.status == '4'"
  32. @click="startToInfrared(scope.row)"
  33. >
  34. <!--@click="openStartDialog(scope.row)" -->
  35. 开始
  36. </el-button>
  37. <el-popconfirm title="确定终止此任务吗?" @confirm="stopToInfrared(scope.row)" v-if="scope.row.status == '1'">
  38. <template #reference>
  39. <el-button type="primary" link icon="Delete"> 终止</el-button>
  40. </template>
  41. </el-popconfirm>
  42. <el-button
  43. type="primary"
  44. link
  45. icon="View"
  46. v-auth="['demo:DataSeq:query']"
  47. v-if="scope.row.status == '2' && scope.row.type == AlgorithmType2['预测/推理']"
  48. @click="preview(scope.row)"
  49. >
  50. 预览
  51. </el-button>
  52. <el-button
  53. type="primary"
  54. link
  55. icon="View"
  56. v-auth="['demo:ToInfrared:download']"
  57. v-if="scope.row.status == '2'"
  58. @click="dowloadToInfrared(scope.row)"
  59. >
  60. 下载
  61. </el-button>
  62. <el-button
  63. type="primary"
  64. link
  65. icon="View"
  66. v-auth="['demo:ToInfrared:download']"
  67. v-if="scope.row.status == '2'"
  68. @click="showToInfraredModel(scope.row.id)"
  69. >
  70. 模型
  71. </el-button>
  72. <el-button
  73. type="primary"
  74. link
  75. icon="View"
  76. v-auth="['demo:toInfrared:query']"
  77. @click="viewLogRef.handleOpen(scope.row.id)"
  78. v-if="scope.row.status != '0'"
  79. >
  80. 日志
  81. </el-button>
  82. <!-- <el-button type="primary" link icon="View" v-auth="['demo:toInfrared:query']" @click="openDialog(3, '查看', scope.row)"> 查看 </el-button> -->
  83. <!-- <el-button type="primary" link icon="EditPen"v-auth="['demo:toInfrared:edit']" @click="openDialog(2, '编辑', scope.row)"> 编辑 </el-button> -->
  84. <el-button
  85. type="primary"
  86. link
  87. icon="Delete"
  88. v-auth="['demo:toInfrared:remove']"
  89. @click="deleteToInfrared(scope.row)"
  90. :disabled="scope.row.status == '1'"
  91. >
  92. 删除
  93. </el-button>
  94. </template>
  95. </ProTable>
  96. <FormDialog ref="formDialogRef" />
  97. <ImportExcel ref="dialogRef" />
  98. <PreviewImages :visible="dialogVisible" :urls="imageUrls" @close="dialogVisible = false" />
  99. <ViewLog ref="viewLogRef" :get-log-api="getLogToInfraredApi" />
  100. <el-dialog v-model="showModelDialogVisible" title="模型列表" width="900">
  101. <el-scrollbar ref="scrollbarRef" id="scrollbarRef1" height="500px">
  102. <template v-for="model in model_list" :key="model">
  103. <el-card style="width: 100%; margin-bottom: 10px">
  104. <el-form label-width="130px" label-position="left">
  105. <el-form-item label="Model Name">
  106. {{ model.name }}
  107. </el-form-item>
  108. <el-form-item label="Model Path">
  109. {{ model.path }}
  110. </el-form-item>
  111. <el-form-item label="Model Size">
  112. {{ model.size }}
  113. </el-form-item>
  114. <el-form-item label="操作">
  115. <el-link :href="model.url" type="primary" icon="Download" :underline="false" target="_blank" style="margin-right: 20px"
  116. >下载
  117. </el-link>
  118. <el-button type="success" link @click="addToInfraredModel(model.path)"
  119. ><el-icon><Plus /></el-icon>添加模型</el-button
  120. >
  121. </el-form-item>
  122. </el-form>
  123. </el-card>
  124. </template>
  125. </el-scrollbar>
  126. </el-dialog>
  127. </div>
  128. </template>
  129. <script setup lang="tsx" name="ToInfrared">
  130. import { ref, reactive, onMounted, Ref } from 'vue'
  131. import { useHandleData } from '@/hooks/useHandleData'
  132. import { useDownload } from '@/hooks/useDownload'
  133. import { ElMessage, ElMessageBox } from 'element-plus'
  134. import ProTable from '@/components/ProTable/index.vue'
  135. import ImportExcel from '@/components/ImportExcel/index.vue'
  136. import FormDialog from '@/components/FormDialog/index.vue'
  137. import { ProTableInstance, ColumnProps } from '@/components/ProTable/interface'
  138. import {
  139. listToInfraredApi,
  140. delToInfraredApi,
  141. addToInfraredApi,
  142. updateToInfraredApi,
  143. importTemplateApi,
  144. importToInfraredDataApi,
  145. exportToInfraredApi,
  146. startToInfraredApi,
  147. stopToInfraredApi,
  148. dowloadToInfraredApi,
  149. getToInfraredApi,
  150. getLogToInfraredApi,
  151. showToInfraredModelApi
  152. } from '@/api/modules/demo/toInfrared'
  153. import { getImagesApi, listDataSeqApi } from '@/api/modules/demo/DataSeq'
  154. import { enumAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
  155. import { getAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
  156. import { enumAlgorithmConfigTrackApi } from '@/api/modules/demo/AlgorithmConfigTrack'
  157. import statusEnums from '@/utils/status'
  158. import { AlgorithmType, SubSystem, SubSystem__, enumsAlgorithmType, enumsSubSystem, AlgorithmType2 } from '@/views/demo/utils'
  159. import PreviewImages from '@/views/demo/components/PreviewImages.vue'
  160. import { Row } from 'element-plus/es/components/table-v2/src/components'
  161. import { addAlgorithmModelTrackApi } from '@/api/modules/demo/AlgorithmModelTrack'
  162. import ViewLog from '@/views/demo/components/ViewLog.vue'
  163. const enumsAlgorithmConfigTrack = ref<any>([])
  164. onMounted(async () => {
  165. const result = await enumAlgorithmConfigTrackApi()
  166. enumsAlgorithmConfigTrack.value = []
  167. const tmp_data: any = result['data']
  168. for (const item of tmp_data) {
  169. if (item.subsystem === SubSystem__['可见光转红外'] && item.type === AlgorithmType2['预测/推理']) {
  170. item['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']]
  171. enumsAlgorithmConfigTrack.value.push(item)
  172. }
  173. }
  174. return result['data']
  175. })
  176. const setItemsOptions222 = () => {
  177. itemsOptions = [
  178. {
  179. label: '算法',
  180. prop: 'algorithmId',
  181. rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
  182. compOptions: {
  183. elTagName: 'select',
  184. placeholder: '请输入算法',
  185. enum: enumsAlgorithmConfigTrack
  186. }
  187. },
  188. {
  189. label: '子系统',
  190. prop: 'subSystem',
  191. rules: [{ required: true, message: '子系统不能为空', trigger: 'blur' }],
  192. compOptions: {
  193. disabled: true,
  194. elTagName: 'select',
  195. placeholder: '请输入子系统',
  196. enum: enumsSubSystem
  197. }
  198. },
  199. {
  200. label: '模型名称',
  201. prop: 'modelName',
  202. rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
  203. compOptions: {
  204. placeholder: '请输入模型名称'
  205. }
  206. },
  207. {
  208. label: '模型路径',
  209. prop: 'modelPath',
  210. rules: [{ required: false, message: '模型文件不能为空', trigger: 'blur' }],
  211. compOptions: {
  212. placeholder: '请输入模型名称',
  213. disabled: true
  214. }
  215. },
  216. {
  217. label: '备注',
  218. prop: 'remarks',
  219. rules: [{ required: false, message: '备注不能为空', trigger: 'blur' }],
  220. compOptions: {
  221. placeholder: '请输入备注'
  222. }
  223. }
  224. ]
  225. }
  226. const addToInfraredModel = async (modelPath: string) => {
  227. let res = { data: { modelPath, subSystem: SubSystem__['可见光转红外'], type: AlgorithmType2['预测/推理'] } }
  228. // 重置表单
  229. setItemsOptions222()
  230. const params = {
  231. title: '添加模型',
  232. width: 580,
  233. isEdit: true,
  234. itemsOptions: itemsOptions,
  235. model: res.data,
  236. api: addAlgorithmModelTrackApi,
  237. getTableList: proTable.value?.getTableList
  238. }
  239. formDialogRef.value?.openDialog(params)
  240. }
  241. const showModelDialogVisible = ref(false)
  242. const model_list: Ref<any> = ref([
  243. // {
  244. // id: 1,
  245. // name: '1',
  246. // path: '/home/11',
  247. // size: '123123MB',
  248. // url: 'http://localhost:9090/profile/upload/2024/10/27/1_1729404909511_20241027153840A001.zip'
  249. // },
  250. // {
  251. // id: 2,
  252. // name: '1',
  253. // path: '/home/11',
  254. // size: '123123MB',
  255. // url: 'http://localhost:9090/profile/upload/2024/10/27/1_1729404909511_20241027153840A001.zip'
  256. // },
  257. // {
  258. // id: 3,
  259. // name: '1',
  260. // path: '/home/11',
  261. // size: '123123MB',
  262. // url: 'http://localhost:9090/profile/upload/2024/10/27/1_1729404909511_20241027153840A001.zip'
  263. // },
  264. // {
  265. // id: 4,
  266. // name: '1',
  267. // path: '/home/11',
  268. // size: '123123MB',
  269. // url: 'http://localhost:9090/profile/upload/2024/10/27/1_1729404909511_20241027153840A001.zip'
  270. // }
  271. ])
  272. const showToInfraredModel = async (id: any) => {
  273. const res: any = await showToInfraredModelApi(id)
  274. model_list.value = res.data
  275. showModelDialogVisible.value = true
  276. }
  277. const viewLogRef = ref()
  278. const dialogVisible = ref(false)
  279. const imageUrls = ref([])
  280. const preview = async row => {
  281. console.log('showImages:', row.inputOssId)
  282. const data: any = await getImagesApi(row.inputOssId, '_to_infrared', false, 'predict')
  283. imageUrls.value = data.data
  284. dialogVisible.value = true
  285. }
  286. const openModelDialog = async row => {
  287. const algorithmModelId = row.algorithmModelId
  288. const result: any = await getAlgorithmModelTrackApi(algorithmModelId)
  289. // console.log(result.data)
  290. setItemsOptionsModel()
  291. const params = {
  292. title: '模型',
  293. width: 580,
  294. isEdit: false,
  295. itemsOptions: itemsOptions,
  296. model: result.data,
  297. api: updateToInfraredApi,
  298. getTableList: proTable.value?.getTableList
  299. }
  300. formDialogRef.value?.openDialog(params)
  301. }
  302. const startToInfrared = async (params: any) => {
  303. const res: any = await startToInfraredApi(params.id)
  304. if (res.code === 200) {
  305. ElMessage.success('任务已开始,请等待完成!')
  306. } else {
  307. ElMessage.error('任务开始失败,请检查!')
  308. }
  309. proTable.value?.getTableList()
  310. }
  311. const stopToInfrared = async (params: any) => {
  312. const res: any = await stopToInfraredApi(params.id)
  313. if (res.code === 200) {
  314. ElMessage.success('终止任务成功!')
  315. } else {
  316. ElMessage.error('终止任务失败,请检查!')
  317. }
  318. proTable.value?.getTableList()
  319. }
  320. const dowloadToInfrared = async (params: any) => {
  321. if (params.type == AlgorithmType2['训练']) {
  322. await useDownload(dowloadToInfraredApi, params.name, params.id, true, '.pt')
  323. } else if (params.type == AlgorithmType2['预测/推理']) {
  324. await useDownload(dowloadToInfraredApi, params.name, params.id, true, '.zip')
  325. }
  326. }
  327. const openStartDialog = async (row: any) => {
  328. let res = { data: {} }
  329. if (row?.id) {
  330. res = await getToInfraredApi(row?.id || null)
  331. }
  332. // 重置表单
  333. setItemsOptions2()
  334. const params = {
  335. title: '开始任务',
  336. width: 580,
  337. isEdit: true,
  338. itemsOptions: itemsOptions,
  339. model: res.data,
  340. api: startToInfraredApi,
  341. getTableList: proTable.value?.getTableList
  342. }
  343. formDialogRef.value?.openDialog(params)
  344. }
  345. // ProTable 实例
  346. const proTable = ref<ProTableInstance>()
  347. // 删除可见光转红外信息
  348. const deleteToInfrared = async (params: any) => {
  349. await useHandleData(delToInfraredApi, params.id, '删除【' + params.id + '】可见光转红外')
  350. proTable.value?.getTableList()
  351. }
  352. // 批量删除可见光转红外信息
  353. const batchDelete = async (ids: string[]) => {
  354. await useHandleData(delToInfraredApi, ids, '删除所选可见光转红外信息')
  355. proTable.value?.clearSelection()
  356. proTable.value?.getTableList()
  357. }
  358. // 导出可见光转红外列表
  359. const downloadFile = async () => {
  360. ElMessageBox.confirm('确认导出可见光转红外数据?', '温馨提示', { type: 'warning' }).then(() =>
  361. useDownload(exportToInfraredApi, '可见光转红外列表', proTable.value?.searchParam)
  362. )
  363. }
  364. // 批量添加可见光转红外
  365. const dialogRef = ref<InstanceType<typeof ImportExcel> | null>(null)
  366. const batchAdd = () => {
  367. const params = {
  368. title: '可见光转红外',
  369. tempApi: importTemplateApi,
  370. importApi: importToInfraredDataApi,
  371. getTableList: proTable.value?.getTableList
  372. }
  373. dialogRef.value?.acceptParams(params)
  374. }
  375. const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
  376. // 打开弹框的功能
  377. const openDialog = async (type: number, title: string, row?: any) => {
  378. let res = { data: {} }
  379. if (row?.id) {
  380. res = await getToInfraredApi(row?.id || null)
  381. }
  382. // 重置表单
  383. setItemsOptions()
  384. const params = {
  385. title,
  386. width: 580,
  387. isEdit: type !== 3,
  388. itemsOptions: itemsOptions,
  389. model: type == 1 ? {} : res.data,
  390. api: type == 1 ? addToInfraredApi : updateToInfraredApi,
  391. getTableList: proTable.value?.getTableList
  392. }
  393. formDialogRef.value?.openDialog(params)
  394. }
  395. // 表格配置项
  396. const columns = reactive<ColumnProps<any>[]>([
  397. { type: 'selection', fixed: 'left', width: 70 },
  398. { prop: 'id', label: '主键ID', width: 180 },
  399. {
  400. prop: 'name',
  401. label: '任务名称',
  402. search: {
  403. el: 'input'
  404. },
  405. width: 150
  406. },
  407. {
  408. prop: 'status',
  409. label: '任务状态',
  410. search: {
  411. el: 'select'
  412. },
  413. tag: true,
  414. enum: statusEnums,
  415. width: 150
  416. },
  417. {
  418. prop: 'type',
  419. label: '类型',
  420. tag: true,
  421. enum: enumsAlgorithmType,
  422. width: 120
  423. },
  424. {
  425. prop: 'subsystem',
  426. label: '分系统',
  427. tag: true,
  428. enum: enumsSubSystem,
  429. width: 200
  430. },
  431. {
  432. prop: 'algorithmName',
  433. label: '算法名称',
  434. width: 200
  435. },
  436. {
  437. prop: 'modelName',
  438. label: '模型名称',
  439. width: 200
  440. },
  441. // {
  442. // prop: 'algorithmModelId',
  443. // label: '模型',
  444. // search: {
  445. // el: 'input'
  446. // },
  447. // width: 150
  448. // },
  449. {
  450. prop: 'startTime',
  451. label: '开始时间',
  452. width: 180
  453. },
  454. {
  455. prop: 'endTime',
  456. label: '结束时间',
  457. width: 180
  458. },
  459. {
  460. prop: 'costSecond',
  461. label: '耗时',
  462. width: 120
  463. },
  464. {
  465. prop: 'log',
  466. label: '日志',
  467. width: 120
  468. },
  469. {
  470. prop: 'outputPath',
  471. label: '输出路径',
  472. width: 120
  473. },
  474. {
  475. prop: 'remarks',
  476. label: '备注',
  477. search: {
  478. el: 'input'
  479. },
  480. width: 120
  481. },
  482. { prop: 'operation', label: '操作', width: 230, fixed: 'right' }
  483. ])
  484. // 表单配置项
  485. let itemsOptions: ProForm.ItemsOptions[] = []
  486. const setItemsOptions = () => {
  487. itemsOptions = [
  488. {
  489. label: '任务名称',
  490. prop: 'name',
  491. rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
  492. compOptions: {
  493. placeholder: '请输入任务名称'
  494. }
  495. },
  496. {
  497. label: '选择数据集',
  498. prop: 'inputOssId',
  499. rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
  500. compOptions: {
  501. elTagName: 'select',
  502. placeholder: '请选择或者上传数据集',
  503. enum: getImageDataList,
  504. clearable: true
  505. }
  506. },
  507. {
  508. label: '上传数据集',
  509. prop: 'inputOssId',
  510. rules: [{ required: false, message: '数据集不能为空', trigger: 'blur' }],
  511. compOptions: {
  512. elTagName: 'file-upload',
  513. fileSize: 4096,
  514. fileType: ['zip'],
  515. placeholder: '请上传数据集'
  516. }
  517. },
  518. {
  519. label: '选择模型',
  520. prop: 'algorithmModelId',
  521. rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
  522. compOptions: {
  523. elTagName: 'select',
  524. placeholder: '请选择模型',
  525. enum: enumsAlgorithmModelTrack
  526. }
  527. },
  528. {
  529. label: '备注',
  530. prop: 'remarks',
  531. rules: [],
  532. compOptions: {
  533. placeholder: '请输入备注'
  534. }
  535. }
  536. ]
  537. }
  538. const getImageDataList = ref<any>([])
  539. onMounted(async () => {
  540. const qyery = {
  541. subsystem: SubSystem__['可见光转红外'],
  542. pageNum: 1,
  543. pageSize: 25
  544. }
  545. const result: any = await listDataSeqApi(qyery)
  546. const data = result['data']['list']
  547. for (const item of data) {
  548. getImageDataList.value.push({
  549. value: item['inputOssId'],
  550. label: item['name']
  551. })
  552. }
  553. })
  554. const enumsAlgorithmModelTrack = ref<any>([])
  555. onMounted(async () => {
  556. const result: any = await enumAlgorithmModelTrackApi()
  557. // console.log(result.data);
  558. enumsAlgorithmModelTrack.value = []
  559. for (const item of result.data) {
  560. if (SubSystem[item['subsystem']] === '可见光转红外') {
  561. item['label'] = item['label'] + '-' + SubSystem[item['subsystem']] + '-' + AlgorithmType[item['type']] + '-' + item['algorithmName']
  562. enumsAlgorithmModelTrack.value.push(item)
  563. }
  564. }
  565. })
  566. const setItemsOptions2 = () => {
  567. itemsOptions = [
  568. {
  569. label: '任务名称',
  570. prop: 'name',
  571. rules: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
  572. compOptions: {
  573. disabled: true,
  574. placeholder: '请输入任务名称'
  575. }
  576. },
  577. {
  578. label: '选择模型',
  579. prop: 'algorithmModel',
  580. rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
  581. compOptions: {
  582. elTagName: 'select',
  583. placeholder: '请选择模型',
  584. enum: enumsAlgorithmModelTrack
  585. }
  586. },
  587. {
  588. label: '备注',
  589. prop: 'remarks',
  590. rules: [],
  591. compOptions: {
  592. placeholder: '请输入备注'
  593. }
  594. }
  595. ]
  596. }
  597. const setItemsOptionsModel = () => {
  598. itemsOptions = [
  599. {
  600. label: '算法ID',
  601. prop: 'algorithmId',
  602. rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
  603. compOptions: {
  604. disabled: true,
  605. placeholder: '请输入算法'
  606. }
  607. },
  608. {
  609. label: '算法类型',
  610. prop: 'algorithmType',
  611. rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
  612. compOptions: {
  613. disabled: true,
  614. elTagName: 'select',
  615. placeholder: '请输入算法',
  616. enum: enumsAlgorithmConfigTrack
  617. }
  618. },
  619. {
  620. label: '算法参数',
  621. prop: 'parameterConfig',
  622. rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
  623. compOptions: {
  624. placeholder: '请输入模型名称'
  625. }
  626. },
  627. {
  628. label: '模型ID',
  629. prop: 'id',
  630. rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
  631. compOptions: {
  632. placeholder: '请输入模型名称'
  633. }
  634. },
  635. {
  636. label: '模型名称',
  637. prop: 'modelName',
  638. rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
  639. compOptions: {
  640. placeholder: '请输入模型名称'
  641. }
  642. },
  643. {
  644. label: '模型保存路径',
  645. prop: 'modelAddress',
  646. rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
  647. compOptions: {
  648. placeholder: '请输入模型名称'
  649. }
  650. },
  651. {
  652. label: '备注',
  653. prop: 'remarks',
  654. rules: [{ required: false, message: '备注不能为空', trigger: 'blur' }],
  655. compOptions: {
  656. placeholder: '请输入备注'
  657. }
  658. }
  659. ]
  660. }
  661. </script>