index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. <template>
  2. <div class="createTask-bigBox">
  3. <dv-border-box1 ref="borderRef" style="width: 80%; height: calc(100% - 20px); margin: 0 auto">
  4. <el-container style="height: 30px"></el-container>
  5. <el-container>
  6. <span class="span_class">任务名称</span>
  7. <el-input
  8. style="width: 300px"
  9. type="text"
  10. placeholder="请输入任务名称"
  11. v-model="formData.taskName"
  12. >
  13. </el-input>
  14. </el-container>
  15. <el-container style="height: 10px"></el-container>
  16. <el-container>
  17. <span class="span_class">任务类型</span>
  18. <el-radio v-model="formData.taskType" label="1">单数据多算法任务</el-radio>
  19. <el-radio v-model="formData.taskType" label="2">多数据单算法任务</el-radio>
  20. </el-container>
  21. <el-container style="height: 10px"></el-container>
  22. <el-container>
  23. <span class="span_class">算法任务</span>
  24. <el-checkbox-group v-model="formData.tasks">
  25. <el-checkbox label="1">训练</el-checkbox>
  26. <el-checkbox label="2">测试</el-checkbox>
  27. </el-checkbox-group>
  28. </el-container>
  29. <el-container style="height: 10px"></el-container>
  30. <el-container>
  31. <span class="span_class">选择算法</span>
  32. <el-container style="display: flex; flex-direction: column">
  33. <el-container v-for="(item, index) in formData.algorithms" :key="index" style="margin-top: 5px">
  34. <el-select style="width: 200px" v-model="formData.algoIdx[index]" placeholder="请选择" @change="onModelSelect(index)">
  35. <el-option
  36. v-for="(item1,index) in algorithms"
  37. :key="item1.id"
  38. :label="item1.name"
  39. :value="index"
  40. >
  41. </el-option>
  42. </el-select>
  43. <el-button style="margin-left: 20px" @click="showSuperParameterConfig(item, index)">
  44. 超参配置
  45. </el-button>
  46. <el-button @click="showAddModelDialog">
  47. 导入模型
  48. </el-button>
  49. <el-button v-show="formData.algorithms.length>1" @click="removeItem(index)">
  50. 删除算法
  51. </el-button>
  52. <el-button v-show="formData.taskType === '1' && index + 1 === formData.algorithms.length" @click="appendNewItem">
  53. 添加算法
  54. </el-button>
  55. </el-container>
  56. </el-container>
  57. </el-container>
  58. <el-container style="height: 10px"></el-container>
  59. <el-container>
  60. <span class="span_class">选择训练数据</span>
  61. <el-container style="display: flex; flex-direction: column">
  62. <el-container v-for="(item, index) in formData.data" :key="index" style="margin-top: 5px">
  63. <el-button v-show="formData.data" @click="showDataSelectionDialog(index, true)">
  64. 选择批次
  65. </el-button>
  66. <span v-if="!item || item.length === 0" class="span_class" style="color: red; font-size: 15px">未完成</span>
  67. <span v-else class="span_class" style="color: greenyellow; font-size: 15px">已选择</span>
  68. <el-button v-show="formData.data.length>1" style="margin-left: 20px" @click="removeDataItem(index, true)">
  69. 删除数据
  70. </el-button>
  71. <el-button v-show="formData.taskType === '2' && index + 1 === formData.data.length" style="margin-left: 20px" @click="appendNewDataItem(true)">
  72. 添加数据
  73. </el-button>
  74. </el-container>
  75. </el-container>
  76. </el-container>
  77. <el-container style="height: 10px"></el-container>
  78. <el-container>
  79. <span class="span_class">选择测试数据</span>
  80. <el-container style="display: flex; flex-direction: column">
  81. <el-container v-for="(item, index) in formData.testData" :key="index" style="margin-top: 5px">
  82. <el-button v-show="formData.testData" @click="showDataSelectionDialog(index, false)">
  83. 选择批次
  84. </el-button>
  85. <span v-if="!item || item.length === 0" class="span_class" style="color: red; font-size: 15px">未完成</span>
  86. <span v-else class="span_class" style="color: greenyellow; font-size: 15px">已选择</span>
  87. <el-button v-show="formData.testData.length>1" style="margin-left: 20px" @click="removeDataItem(index, false)">
  88. 删除数据
  89. </el-button>
  90. <el-button v-show="formData.taskType === '2' && index + 1 === formData.testData.length" style="margin-left: 20px" @click="appendNewDataItem(false)">
  91. 添加数据
  92. </el-button>
  93. </el-container>
  94. </el-container>
  95. </el-container>
  96. <el-container style="height: 10px"></el-container>
  97. <el-container>
  98. <span class="span_class">是否训练扩增</span>
  99. <el-checkbox v-model="formData.expandData">扩增</el-checkbox>
  100. <el-button v-show="formData.expandData" style="margin-left: 20px" @click="showExpandDataSuperParameterConfig">
  101. 超参配置
  102. </el-button>
  103. </el-container>
  104. <el-form-item style="margin-left: 30px; margin-top: 20px">
  105. <el-button type="primary" @click="submit">
  106. 提交
  107. </el-button>
  108. <el-button @click="cancel">
  109. 取消
  110. </el-button>
  111. </el-form-item>
  112. </dv-border-box1>
  113. <FormDialog ref="formDialogRef" />
  114. <el-dialog
  115. v-model="expandDataDialogVisible"
  116. title="数据扩增超参配置"
  117. >
  118. <!-- <span style="font-size: 16px; color: darkorange; font-weight: bold"> 数据扩增超参 </span>-->
  119. <el-container v-for="(item, index) in expandDataConfig" :key="index" style="margin-top: 5px">
  120. <span class="span_class"> {{ item.name }}</span>
  121. <el-input
  122. style="width: 300px"
  123. type="text"
  124. :placeholder="'请输入'+item.name"
  125. v-model="item.defaultValue"
  126. >
  127. </el-input>
  128. </el-container>
  129. <el-container style="height: 10px"></el-container>
  130. <span class="dialog-footer" >
  131. <el-button type="primary" @click="submitExpandDataConfigDialog">确 定</el-button>
  132. <el-button @click="expandDataDialogVisible = false">取 消</el-button>
  133. </span>
  134. </el-dialog>
  135. <el-dialog
  136. v-model="dialogVisible"
  137. :title="superParameterFormData.title"
  138. >
  139. <span style="font-size: 16px; color: darkorange; font-weight: bold"> 训练超参 </span>
  140. <el-container v-for="(item, index) in superParameterFormData.trainParams" :key="index">
  141. <span class="span_class"> {{ item.name }}</span>
  142. <el-input
  143. style="width: 300px"
  144. type="text"
  145. :placeholder="'请输入'+item.name"
  146. v-model="item.defaultValue"
  147. >
  148. </el-input>
  149. </el-container>
  150. <el-container style="height: 10px"></el-container>
  151. <span style="font-size: 16px; color: darkorange; font-weight: bold"> 验证超参 </span>
  152. <el-container v-for="(item, index) in superParameterFormData.verifyParams" :key="index">
  153. <span class="span_class"> {{ item.name }}</span>
  154. <el-input
  155. style="width: 300px"
  156. type="text"
  157. :placeholder="'请输入'+item.name"
  158. v-model="item.defaultValue"
  159. >
  160. </el-input>
  161. </el-container>
  162. <el-container style="height: 10px"></el-container>
  163. <span style="font-size: 16px; color: darkorange; font-weight: bold"> 测试超参 </span>
  164. <el-container v-for="(item, index) in superParameterFormData.testParams" :key="index">
  165. <span class="span_class"> {{ item.name }}</span>
  166. <el-input
  167. style="width: 300px"
  168. type="text"
  169. :placeholder="'请输入'+item.name"
  170. v-model="item.defaultValue"
  171. >
  172. </el-input>
  173. </el-container>
  174. <el-container style="height: 10px"></el-container>
  175. <span class="dialog-footer" >
  176. <el-button type="primary" @click="submitConfigDialog">确 定</el-button>
  177. <el-button @click="dialogVisible = false">取 消</el-button>
  178. </span>
  179. </el-dialog>
  180. <el-dialog
  181. v-model="dataDialogVisible"
  182. title="选择数据批次"
  183. style="width: 70vw"
  184. >
  185. <el-container>
  186. <el-table
  187. :data="batchDataList"
  188. tooltip-effect="dark"
  189. style="width: 100%"
  190. @selection-change="handleSelectionChange"
  191. >
  192. <el-table-column
  193. type="selection"
  194. width="55"
  195. >
  196. </el-table-column>
  197. <el-table-column
  198. prop="batchNum"
  199. label="所有批次"
  200. width="120"
  201. >
  202. </el-table-column>
  203. <el-table-column
  204. prop="batchSize"
  205. label="数量"
  206. width="80"
  207. >
  208. </el-table-column>
  209. </el-table>
  210. <el-container style="margin-left: 10px; margin-right: 10px; display: flex; flex-direction: column; justify-content: center">
  211. <el-button type="primary" :disabled="!canSelect" @click="clickSelectData"> {{ '=>' }} </el-button>
  212. <el-container style="height: 10px"></el-container>
  213. <el-button type="primary" :disabled="!canDeselect" @click="clickDeselectData"> {{ '<=' }} </el-button>
  214. </el-container>
  215. <el-table
  216. :data="selectedBatchDataList"
  217. tooltip-effect="dark"
  218. style="width: 100%"
  219. @selection-change="handleDeselectionChange"
  220. >
  221. <el-table-column
  222. type="selection"
  223. width="55"
  224. >
  225. </el-table-column>
  226. <el-table-column
  227. prop="batchNum"
  228. label="已选批次"
  229. width="120"
  230. >
  231. </el-table-column>
  232. <el-table-column
  233. prop="batchSize"
  234. label="数量"
  235. width="80"
  236. >
  237. </el-table-column>
  238. </el-table>
  239. </el-container>
  240. <el-container style="height: 10px"></el-container>
  241. <span class="dialog-footer" >
  242. <el-button type="primary" @click="submitDataDialog">确 定</el-button>
  243. <el-button @click="dataDialogVisible = false">取 消</el-button>
  244. </span>
  245. </el-dialog>
  246. </div>
  247. </template>
  248. <script setup lang="ts">
  249. import {reactive, ref, onMounted, computed} from "vue";
  250. import {addModelApi} from "@/api/modules/ag/model";
  251. import {createTaskApi, getAlgorithmOptionApi} from "@/api/modules/task/task";
  252. import FormDialog from "@/components/FormDialog/index.vue";
  253. import { useRouter } from 'vue-router'
  254. import {listTaskConfigurationApi} from "@/api/modules/task/taskConfiguration";
  255. import {batchListDataApi} from "@/api/modules/demo/data";
  256. import {listDataApi} from "@/api/modules/system/dictData";
  257. import {ElMessage} from "element-plus";
  258. const valid = data => {
  259. let ret = {
  260. code: 400,
  261. message: 'OK'
  262. }
  263. if (!data.taskName || data.taskName.length === 0) {
  264. ret.message = '任务名称不能为空'
  265. return ret
  266. }
  267. if (!data.taskItemList || data.taskItemList.length === 0) {
  268. ret.message = '请选择算法任务'
  269. return ret
  270. }
  271. data.algTaskList.forEach(obj => {
  272. if (!obj || !obj.id) {
  273. ret.message = '请选择算法模型'
  274. }
  275. })
  276. if (ret.message !== 'OK') {
  277. return ret
  278. }
  279. if (data.taskItemList.includes('1')) {
  280. data.trainBatchNumList.forEach(obj => {
  281. if (!obj) {
  282. ret.message = '请选择训练数据集'
  283. }
  284. })
  285. if (ret.message !== 'OK') {
  286. return ret
  287. }
  288. }
  289. if (data.taskItemList.includes('2')) {
  290. data.testBatchNumList.forEach(obj => {
  291. if (!obj) {
  292. ret.message = '请选择测试数据集'
  293. }
  294. })
  295. if (ret.message !== 'OK') {
  296. return ret
  297. }
  298. }
  299. if (data.hasTrainAugmentation) {
  300. if (!data.trainAugmentationParams || data.trainAugmentationParams.length === 0) {
  301. ret.message = '请配置扩增参数'
  302. return ret
  303. }
  304. }
  305. ret.code = 200
  306. return ret
  307. }
  308. const submit = () => {
  309. const params = {
  310. taskName: formData.taskName,
  311. taskType: formData.taskType,
  312. taskItemList: formData.tasks,
  313. algTaskList: formData.algorithms,
  314. trainBatchNumList: formData.data,
  315. testBatchNumList: formData.testData,
  316. hasTrainAugmentation: formData.expandData,
  317. trainAugmentationParams: formData.expandConfig
  318. }
  319. let result = valid(params)
  320. // console.log(result)
  321. if (result.code !== 200) {
  322. ElMessage.error(result.message)
  323. return
  324. }
  325. params.algTaskList.forEach(obj => {
  326. obj.algorithmId = obj.id;
  327. // if (!obj.trainParams) {
  328. // return
  329. // }
  330. obj.params = JSON.stringify(JSON.parse(obj.trainParams)) + ";;;" +
  331. JSON.stringify(JSON.parse(obj.verifyParams)) + ";;;" +
  332. JSON.stringify(JSON.parse(obj.testParams))
  333. })
  334. // console.log('submit', params)
  335. createTaskApi(params)
  336. .then(res => {
  337. // console.log(res)
  338. if (res.code !== 200) {
  339. ElMessage.error(res.msg)
  340. } else {
  341. router.push(`/index`)
  342. }
  343. })
  344. .catch(err => {
  345. console.log(err)
  346. })
  347. }
  348. const loadExpandDataParams = () => {
  349. listDataApi({
  350. dictType: 'expand_data_params',
  351. pageNum: 1,
  352. pageSize: 10000
  353. })
  354. .then(res => {
  355. // console.log(res)
  356. expandDataConfig.value = reactive([])
  357. res.data.list.forEach(obj => {
  358. expandDataConfig.value.push({
  359. name: obj.dictLabel,
  360. defaultValue: obj.dictValue
  361. })
  362. })
  363. expandDataDialogVisible.value = true
  364. })
  365. .catch(err => {
  366. console.log(err)
  367. })
  368. }
  369. const showExpandDataSuperParameterConfig = () => {
  370. loadExpandDataParams()
  371. }
  372. // 数据扩增超参修改保存
  373. const submitExpandDataConfigDialog = () => {
  374. // console.log(expandDataConfig)
  375. formData.expandConfig = JSON.stringify(expandDataConfig.value)
  376. expandDataDialogVisible.value = false
  377. }
  378. const expandDataDialogVisible = ref(false)
  379. let expandDataConfig = ref(reactive([
  380. // {
  381. // name: 'config1',
  382. // defaultValue: 'a'
  383. // }
  384. ]))
  385. const submitConfigDialog = () => {
  386. dialogVisible.value = false
  387. formData.algorithms[superParameterFormData.index].trainParams = JSON.stringify(superParameterFormData.trainParams)
  388. formData.algorithms[superParameterFormData.index].verifyParams = JSON.stringify(superParameterFormData.verifyParams)
  389. formData.algorithms[superParameterFormData.index].testParams = JSON.stringify(superParameterFormData.testParams)
  390. }
  391. // 选择批次的数据结果
  392. const submitDataDialog = () => {
  393. // console.log(selectedBatchDataList.value)
  394. let val = ''
  395. for (let i = 0; i < selectedBatchDataList.value.length; i++) {
  396. val += selectedBatchDataList.value[i].batchNum + ','
  397. }
  398. if (bIsTrainData.value) {
  399. formData.data[selectDataIndex] = val.substring(0, val.length - 1)
  400. } else {
  401. formData.testData[selectDataIndex] = val.substring(0, val.length - 1)
  402. }
  403. dataDialogVisible.value = false
  404. }
  405. const canSelect = computed(() => {
  406. // console.log(tempSelectedBatchDataList)
  407. return tempSelectedBatchDataList.value.length > 0
  408. })
  409. const canDeselect = computed(() => {
  410. return tempDeselectedBatchDataList.value.length > 0
  411. })
  412. onMounted(() => {
  413. listTaskConfigurationApi({ pageNum: 1, pageSize: 10000 })
  414. .then(res => {
  415. // console.log(res)
  416. algorithms = reactive(res.data.list)
  417. })
  418. batchListDataApi()
  419. .then(res => {
  420. // console.log(res)
  421. queryBatchData.value = reactive(res.data)
  422. })
  423. })
  424. let queryBatchData = ref(reactive([]))
  425. const handleSelectionChange = data => {
  426. tempSelectedBatchDataList.value = reactive(data)
  427. // console.log(data)
  428. }
  429. const handleDeselectionChange = data => {
  430. tempDeselectedBatchDataList.value = reactive(data)
  431. // console.log(data)
  432. }
  433. const clickSelectData = () => {
  434. let set = new Set
  435. for (let i = 0; i < tempSelectedBatchDataList.value.length; i++) {
  436. set.add(tempSelectedBatchDataList.value[i].batchNum)
  437. selectedBatchDataList.value.push(tempSelectedBatchDataList.value[i])
  438. }
  439. let newArray = []
  440. for (let i = 0; i < batchDataList.value.length; i++) {
  441. if (!set.has(batchDataList.value[i].batchNum)) {
  442. newArray.push(batchDataList.value[i])
  443. }
  444. }
  445. batchDataList.value = reactive(newArray)
  446. // console.log(batchDataList)
  447. }
  448. const clickDeselectData = () => {
  449. let set = new Set
  450. for (let i = 0; i < tempDeselectedBatchDataList.value.length; i++) {
  451. set.add(tempDeselectedBatchDataList.value[i].batchNum)
  452. batchDataList.value.push(tempDeselectedBatchDataList.value[i])
  453. }
  454. let newArray = []
  455. for (let i = 0; i < selectedBatchDataList.value.length; i++) {
  456. if (!set.has(selectedBatchDataList.value[i].batchNum)) {
  457. newArray.push(selectedBatchDataList.value[i])
  458. }
  459. }
  460. selectedBatchDataList.value = reactive(newArray)
  461. }
  462. const router = useRouter()
  463. let bIsTrainData = ref(false)
  464. let dialogVisible = ref(false)
  465. let batchDataList = ref(reactive([]))
  466. let selectedBatchDataList = ref(reactive([]))
  467. let tempSelectedBatchDataList = ref(reactive([]))
  468. let tempDeselectedBatchDataList = ref(reactive([]))
  469. const formData = reactive({
  470. taskName: null,
  471. taskType: '1',
  472. tasks: [],
  473. algorithms: [
  474. {}
  475. ],
  476. algoIdx: [
  477. null
  478. ],
  479. // 训练数据
  480. data: [
  481. null
  482. ],
  483. // 测试数据
  484. testData: [
  485. null
  486. ],
  487. expandData: false,
  488. expandConfig: ''
  489. })
  490. let selectDataIndex = null
  491. const dataDialogVisible = ref(false)
  492. const showDataSelectionDialog = (index, isTrainData) => {
  493. bIsTrainData.value = isTrainData
  494. batchDataList.value = queryBatchData.value
  495. selectedBatchDataList.value = reactive([])
  496. tempSelectedBatchDataList.value = reactive([])
  497. tempDeselectedBatchDataList.value = reactive([])
  498. selectDataIndex = index
  499. dataDialogVisible.value = true
  500. }
  501. let superParameterFormData = reactive({})
  502. const showSuperParameterConfig = (item, index) => {
  503. superParameterFormData = reactive({
  504. index: index,
  505. trainParams: JSON.parse(item.trainParams),
  506. testParams: JSON.parse(item.testParams),
  507. verifyParams: JSON.parse(item.verifyParams),
  508. title: '超参配置'
  509. })
  510. // console.log(superParameterFormData)
  511. dialogVisible.value = true
  512. }
  513. let algorithms = reactive([])
  514. const onModelSelect = (index) => {
  515. formData.algorithms[index] = algorithms[formData.algoIdx[index]]
  516. }
  517. const formDialogRef = ref<InstanceType<typeof FormDialog> | null>(null)
  518. const showAddModelDialog = () => {
  519. getAlgorithmOptionApi().then(res => {
  520. let allAgloData = {
  521. value: res.data
  522. }
  523. const params = {
  524. title: '算法模型配置',
  525. width: 580,
  526. isEdit: true,
  527. itemsOptions: [
  528. {
  529. label: '算法',
  530. prop: 'algorithmId',
  531. rules: [{ required: true, message: '算法不能为空', trigger: 'blur' }],
  532. compOptions: {
  533. elTagName: 'select',
  534. labelKey: 'name',
  535. valueKey: 'id',
  536. enum: allAgloData.value,
  537. placeholder: '请选择算法'
  538. }
  539. },
  540. {
  541. label: '模型名称',
  542. prop: 'modelName',
  543. rules: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
  544. compOptions: {
  545. placeholder: '请输入模型名称'
  546. }
  547. },
  548. {
  549. label: '模型',
  550. prop: 'modelAddress',
  551. rules: [{ required: true, message: '模型不能为空', trigger: 'blur' }],
  552. compOptions: {
  553. elTagName: 'slot'
  554. }
  555. },
  556. {
  557. label: '训练样本数',
  558. prop: 'sampleNumber',
  559. compOptions: {
  560. placeholder: '请输入训练样本数'
  561. }
  562. },
  563. {
  564. label: '训练循环次数',
  565. prop: 'cycleEpoch',
  566. compOptions: {
  567. placeholder: '请输入训练循环次数'
  568. }
  569. },
  570. {
  571. label: '备注',
  572. prop: 'remarks',
  573. compOptions: {
  574. placeholder: '请输入备注'
  575. }
  576. }
  577. ],
  578. model: {},
  579. api: addModelApi
  580. }
  581. formDialogRef.value?.openDialog(params)
  582. })
  583. }
  584. const appendNewItem = () => {
  585. formData.algorithms.push({})
  586. formData.algoIdx.push(null)
  587. }
  588. const appendNewDataItem = isTrainData => {
  589. if (isTrainData) {
  590. formData.data.push([])
  591. } else {
  592. formData.testData.push([])
  593. }
  594. }
  595. const removeItem = idx => {
  596. formData.algorithms.splice(idx, 1)
  597. formData.algoIdx.splice(idx, 1)
  598. }
  599. const removeDataItem = (idx, isTrainData) => {
  600. if (isTrainData) {
  601. formData.data.splice(idx, 1)
  602. } else {
  603. formData.testData.splice(idx, 1)
  604. }
  605. }
  606. const cancel = () => {
  607. // console.log('cancel')
  608. router.push(`/index`)
  609. }
  610. </script>
  611. <style scoped>
  612. .createTask-bigBox {
  613. width: 100%;
  614. height: 100%;
  615. overflow: hidden;
  616. background-image: url('../../../assets/taaisImg/53bg.png');
  617. background-repeat: no-repeat;
  618. background-size: 100% 100%;
  619. }
  620. .span_class {
  621. width: 120px;
  622. font-size: 13px;
  623. display: flex;
  624. align-self: center;
  625. justify-content: center
  626. }
  627. </style>