index.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. <template>
  2. <div>
  3. <el-container style="width:98%;height: 90vh;margin-left:1%;padding-top: 1%;">
  4. <DeptTree :deptOptions="deptOptions" :leftWidth="leftWidth" :placeholder="'请输入数据开发类目名称'" ref="DeptTreeRef"
  5. @node-click="handleNodeClick" />
  6. <el-main style="margin-left: 1%;">
  7. <div v-show="showSearch">
  8. <el-form style="width: 100%;" class="btn-style" :model="queryParams" ref="queryRef" :inline="true" label-width="75px"
  9. v-show="showSearch" @submit.prevent>
  10. <el-form-item label="任务名称" prop="name">
  11. <el-input class="el-form-input-width" v-model="queryParams.name" placeholder="请输入任务名称" clearable
  12. @keyup.enter="handleQuery" />
  13. </el-form-item>
  14. <el-form-item label="任务状态" prop="status">
  15. <el-select style="width: 10vw" v-model="queryParams.status" placeholder="请选择任务状态" clearable class="el-form-input-width">
  16. <el-option v-for="dict in dpp_etl_task_status" :key="dict.value" :label="dict.label"
  17. :value="dict.value" />
  18. </el-select>
  19. </el-form-item>
  20. <el-form-item label="执行引擎" prop="datasourceType">
  21. <el-select style="width: 10vw" v-model="queryParams.datasourceType" placeholder="请选择执行引擎" clearable
  22. class="el-form-input-width">
  23. <el-option v-for="dict in typaOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
  24. </el-select>
  25. </el-form-item>
  26. <el-form-item label="处理类型" prop="processType">
  27. <el-select style="width: 10vw" v-model="queryParams.processType" placeholder="请选择处理类型" clearable class="el-form-input-width">
  28. <el-option label="流处理" value="1" />
  29. <el-option label="批处理" value="2" />
  30. </el-select>
  31. </el-form-item>
  32. <el-form-item>
  33. <el-button plain type="primary" @click="handleQuery" @mousedown="(e) => e.preventDefault()">
  34. <i class="iconfont-mini icon-a-zu22377 mr5"></i>查询
  35. </el-button>
  36. <el-button @click="resetQuery" @mousedown="(e) => e.preventDefault()">
  37. <i class="iconfont-mini icon-a-zu22378 mr5"></i>重置
  38. </el-button>
  39. </el-form-item>
  40. </el-form>
  41. </div>
  42. <div class="pagecont-bottom">
  43. <div class="justify-between mb15">
  44. <el-row :gutter="15" class="btn-style">
  45. <el-col :span="1.5">
  46. <el-button type="primary" plain @click="handleAdd" >
  47. <i class="iconfont-mini icon-xinzeng mr5"></i>新增
  48. </el-button>
  49. </el-col>
  50. </el-row>
  51. </div>
  52. <el-table stripe v-loading="loading" :data="dppEtlTaskList" :default-sort="defaultSort"
  53. @sort-change="handleSortChange">
  54. <el-table-column v-if="getColumnVisibility(0)" label="编号" width="80" align="left" prop="id" />
  55. <el-table-column v-if="getColumnVisibility(1)" label="任务名称" :show-overflow-tooltip="{ effect: 'light' }"
  56. align="left" prop="name" width="200">
  57. <template #default="scope">
  58. <div class="justify">
  59. <span>{{ scope.row.name || "-" }}</span>
  60. </div>
  61. </template>
  62. </el-table-column>
  63. <el-table-column v-if="getColumnVisibility(4)" label="任务类目" :show-overflow-tooltip="true" align="left"
  64. prop="catName" width="120">
  65. <template #default="scope">
  66. {{ scope.row.catName || "-" }}
  67. </template>
  68. </el-table-column>
  69. <el-table-column v-if="getColumnVisibility(3)" width="100" label="执行引擎" align="left" prop="datasourceType">
  70. <template #default="scope">
  71. <el-tag v-if="getExecutionType(scope.row.datasourceType)"
  72. :type="getExecutionType(scope.row.datasourceType).elTagType">
  73. {{ getExecutionType(scope.row.datasourceType).label }}
  74. </el-tag>
  75. <dict-tag v-else :options="datasource_type" :value="scope.row.datasourceType" />
  76. </template>
  77. </el-table-column>
  78. <el-table-column v-if="getColumnVisibility(2)" label="描述" :show-overflow-tooltip="{ effect: 'light' }"
  79. align="left" prop="description" width="240">
  80. <template #default="scope">
  81. {{ scope.row.description || "-" }}
  82. </template>
  83. </el-table-column>
  84. <el-table-column v-if="getColumnVisibility(3)" label="任务状态" width="80" align="left" prop="releaseState">
  85. <template #header>
  86. <div class="justify-center">
  87. <span style="margin-right: 2px;">任务状态</span>
  88. <el-tooltip effect="light" content="代表任务上线,不会执行调度,上线后才可以执行一次" placement="top">
  89. <el-icon class="tip-icon">
  90. <InfoFilled />
  91. </el-icon>
  92. </el-tooltip>
  93. </div>
  94. </template>
  95. <template #default="scope">
  96. <el-switch v-model="scope.row.status" active-color="#13ce66" inactive-color="#ff4949" active-value="1"
  97. :inactive-value="getStatus(scope.row.status)" @change="handleStatusChange(scope.row.id, scope.row)"
  98. :disabled="scope.row.status == '-1'" />
  99. </template>
  100. </el-table-column>
  101. <el-table-column v-if="getColumnVisibility(8)" label="调度状态" width="80" align="left" prop="schedulerState">
  102. <template #header>
  103. <div class="justify-center">
  104. <span style="margin-right: 2px;">调度状态</span>
  105. <el-tooltip effect="light" content="任务状态为启用后可开启调度" placement="top">
  106. <el-icon class="tip-icon">
  107. <InfoFilled />
  108. </el-icon>
  109. </el-tooltip>
  110. </div>
  111. </template>
  112. <template #default="scope">
  113. <el-switch v-model="scope.row.schedulerState" active-color="#13ce66" inactive-color="#ff4949"
  114. active-value="1" inactive-value="0" :disabled="scope.row.status != '1'"
  115. @change="handleschedulerState(scope.row.id, scope.row)" />
  116. </template>
  117. </el-table-column>
  118. <el-table-column v-if="getColumnVisibility(5)" width="100" label="处理类型" align="left" prop="processType">
  119. <template #default="scope">
  120. <dict-tag :options="dpp_etl_task_process_type"
  121. :value="scope.row.datasourceType === 'FlinkStream' ? 1 : 0" />
  122. </template>
  123. </el-table-column>
  124. <el-table-column v-if="getColumnVisibility(9)" label="执行策略" width="80"
  125. :show-overflow-tooltip="{ effect: 'light' }" align="left" prop="executionType">
  126. <template #default="scope">
  127. <dict-tag :options="dpp_etl_task_execution_type" :value="scope.row.executionType" />
  128. </template>
  129. </el-table-column>
  130. <el-table-column v-if="getColumnVisibility(13)" label="调度周期" :show-overflow-tooltip="{ effect: 'light' }"
  131. align="left" prop="cronExpression" width="240">
  132. <template #default="scope">
  133. {{ cronToZh(scope.row.cronExpression) || "-" }}
  134. </template>
  135. </el-table-column>
  136. <el-table-column v-if="getColumnVisibility(14)" label="最近运行时间" width="160" align="left"
  137. prop="lastExecuteTime">
  138. <template #default="scope">
  139. <span>{{
  140. parseTime(
  141. scope.row.lastExecuteTime,
  142. "{y}-{m}-{d} {h}:{i}"
  143. ) || "-"
  144. }}</span>
  145. </template>
  146. </el-table-column>
  147. <el-table-column v-if="getColumnVisibility(10)" width="100px" label="创建人" :show-overflow-tooltip="true"
  148. align="left" prop="createBy">
  149. <template #default="scope">
  150. {{ scope.row.createBy || "-" }}
  151. </template>
  152. </el-table-column>
  153. <!-- sortable="custom" column-key="create_time" :sort-orders="['descending', 'ascending']" -->
  154. <el-table-column v-if="getColumnVisibility(11)" label="创建时间" align="left" prop="create_time" width="150"
  155. sortable="custom" column-key="create_time" :sort-orders="['descending', 'ascending']">
  156. <template #default="scope"> <span>{{ parseTime(scope.row.createTime, "{y}-{m}-{d} {h}:{i}") || "-"
  157. }}</span>
  158. </template>
  159. </el-table-column>
  160. <el-table-column v-if="getColumnVisibility(6)" label="配置状态" :show-overflow-tooltip="true" align="left"
  161. prop="status" width="80">
  162. <template #default="scope">
  163. <el-tag :type="scope.row.status == -1 ? 'warning' : 'success'">{{ scope.row.status == -1 ? "草稿" : "完成"
  164. }}</el-tag>
  165. </template>
  166. </el-table-column>
  167. <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="350">
  168. <template #default="scope">
  169. <el-button link type="primary" icon="Edit" :disabled="scope.row.status == 1"
  170. @click="routeTo('/dpp/task/developTask/edit', scope.row)"
  171. >配置任务</el-button>
  172. <el-button link type="primary" icon="view" @click="
  173. routeTo('/dpp/task/developTask/detail', {
  174. ...scope.row,
  175. info: true,
  176. })
  177. " >详情</el-button>
  178. <el-popover placement="bottom" :width="150" trigger="click">
  179. <template #reference>
  180. <el-button link type="primary" icon="ArrowDown">更多</el-button>
  181. </template>
  182. <!-- 如果是流处理操作列就不展示“调度周期” -->
  183. <div style="width: 100px" class="butgdlist">
  184. <el-button link style="padding-left: 14px" type="primary" icon="Operation"
  185. @click="handleJobLog(scope.row)" :disabled="scope.row.schedulerState == '1'"
  186. v-if="scope.row.processType != 1" >调度周期</el-button>
  187. <!-- 流处理任务状态是启动的,更多中则应该有“停止任务”按钮,并且无法点击“运行实例” -->
  188. <el-button link type="primary" icon="Stopwatch" @click="handleDataView(scope.row)"
  189. v-if="scope.row.processType == 1 && scope.row.status == 1">停止任务</el-button>
  190. <el-button link type="primary" icon="Stopwatch" @click="handleDataView(scope.row)"
  191. v-if="scope.row.processType == 1 && scope.row.status != 1">运行实例</el-button>
  192. <el-button link type="primary" icon="VideoPlay"
  193. :disabled="scope.row.status != 1"
  194. @click="handleExecuteOnce(scope.row)" >执行一次</el-button>
  195. <el-button link type="primary" icon="VideoPlay"
  196. v-if="scope.row.datasourceType === 'FlinkStream' && scope.row.taskInstanceId"
  197. @click="handleExecuteStop(scope.row)" >停止</el-button>
  198. <el-button link type="danger" icon="Delete" :disabled="scope.row.status == 1"
  199. @click="handleDelete(scope.row)" >删除</el-button>
  200. </div>
  201. </el-popover></template>
  202. </el-table-column>
  203. <template #empty>
  204. <div class="emptyBg">
  205. <p>暂无记录</p>
  206. </div>
  207. </template>
  208. </el-table>
  209. <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
  210. v-model:limit="queryParams.pageSize" @pagination="getList" />
  211. </div>
  212. </el-main>
  213. </el-container>
  214. <!-- <instance :visible="DataView" :taskType="3" @update:visible="DataView = $event" @confirm="submitForm" :data="form"
  215. title="运行实例" /> -->
  216. <el-dialog title="调度周期" v-model="openCron" :append-to="$refs['app-container']" destroy-on-close :appendTo="'#app'">
  217. <crontab ref="crontabRef" @hide="openCron = false" @fill="crontabFill" :expression="expression">
  218. </crontab>
  219. </el-dialog>
  220. <add :visible="taskConfigDialogVisible" title="新增任务" @update:visible="taskConfigDialogVisible = $event"
  221. @save="handleSave" @confirm="handleConfirm" :data="taskForm" :userList="userList" :deptOptions="deptOptions"
  222. :info="route.query.info" />
  223. </div>
  224. </template>
  225. <script setup name="DppDevelopTask">
  226. import { onMounted, onUnmounted } from "vue";
  227. import { treeData } from "@/views/dpp/task/developTask/data";
  228. import {
  229. listDppEtlTask,
  230. delDppEtlTask,
  231. addDppEtlTask,
  232. updateDppEtlTask,
  233. updateReleaseSchedule,
  234. updateReleaseJobTask,
  235. releaseTaskCrontab,
  236. startDppEtlTask,
  237. createEtlTaskFront
  238. } from "@/api/dpp/task/index.js";
  239. import { execute } from '@/api/dpp/task';
  240. import { cronToZh } from "@/utils/cronUtils";
  241. import { listAttDataDevCat } from "@/api/att/cat/dataDevCat/dataDevCat";
  242. import Crontab from "@/components/Crontab/index.vue";
  243. // import instance from "@/views/dpp/components/instance.vue";
  244. const userStore = useUserStore();
  245. import { useRoute, useRouter } from "vue-router";
  246. import useUserStore from "@/store/system/user";
  247. import DeptTree from "@/components/DeptTree";
  248. import add from "./add/add.vue";
  249. import { deptUserTree } from "@/api/system/system/user.js";
  250. import { ref } from "vue";
  251. const { proxy } = getCurrentInstance();
  252. const { dpp_etl_task_status, dpp_etl_task_execution_type, datasource_type, dpp_etl_task_process_type } =
  253. proxy.useDict(
  254. "dpp_etl_task_status",
  255. "dpp_etl_task_execution_type",
  256. "datasource_type",
  257. "dpp_etl_task_process_type"
  258. );
  259. const typaOptions = treeData.map((item) => {
  260. return {
  261. ...item,
  262. label: item.label,
  263. value: item.value
  264. }
  265. })
  266. /** 排序触发事件 */
  267. function handleSortChange(column, prop, order) {
  268. queryParams.value.orderByColumn = column.prop;
  269. queryParams.value.isAsc = column.order;
  270. getList();
  271. }
  272. const getExecutionType = (executionType) => {
  273. if (!executionType) return null;
  274. const item = typaOptions.find(i => String(i.value).toLowerCase() === String(executionType).toLowerCase());
  275. if (!item) return null;
  276. return {
  277. ...item,
  278. elTagType: item.elTagType // 默认 info
  279. };
  280. };
  281. const getStatus = (status) => {
  282. if (status == '-1') {
  283. return '-1'
  284. } else {
  285. return '0'
  286. }
  287. }
  288. // 任务配置
  289. const taskConfigDialogVisible = ref(false);
  290. let userList = ref([]);
  291. let taskForm = ref({});
  292. const handleAdd = () => {
  293. taskConfigDialogVisible.value = true;
  294. }
  295. // 保存并关闭
  296. const handleSave = (form) => {
  297. const parms = {
  298. ...form,
  299. projectId: userStore.projectId,
  300. projectCode: userStore.projectCode,
  301. type: "3",//数据开发新增标识
  302. }
  303. createEtlTaskFront(parms).then((res) => {
  304. if (res.code == 200) {
  305. proxy.$modal.msgSuccess("操作成功");
  306. getList();
  307. }
  308. })
  309. }
  310. // 保存并完善
  311. const handleConfirm = (form) => {
  312. const parms = {
  313. ...form,
  314. projectId: userStore.projectId,
  315. projectCode: userStore.projectCode,
  316. type: "3",//数据开发新增标识
  317. }
  318. createEtlTaskFront(parms).then((res) => {
  319. if (res.code == 200) {
  320. proxy.$modal.msgSuccess("操作成功");
  321. getList();
  322. routeTo('/dpp/task/developTask', {
  323. ...res.data,
  324. })
  325. }
  326. })
  327. };
  328. const deptOptions = ref([]);
  329. const leftWidth = ref(300); // 初始左侧宽度
  330. const isResizing = ref(false); // 判断是否正在拖拽
  331. let startX = 0; // 鼠标按下时的初始位置// 初始左侧宽度
  332. const startResize = (event) => {
  333. isResizing.value = true;
  334. startX = event.clientX;
  335. document.addEventListener("mousemove", updateResize);
  336. document.addEventListener("mouseup", stopResize);
  337. };
  338. const stopResize = () => {
  339. isResizing.value = false;
  340. document.removeEventListener("mousemove", updateResize);
  341. document.removeEventListener("mouseup", stopResize);
  342. };
  343. const updateResize = (event) => {
  344. if (isResizing.value) {
  345. const delta = event.clientX - startX; // 计算鼠标移动距离
  346. leftWidth.value += delta; // 修改左侧宽度
  347. startX = event.clientX; // 更新起始位置
  348. // 使用 requestAnimationFrame 来减少页面重绘频率
  349. requestAnimationFrame(() => { });
  350. }
  351. };
  352. /** 下拉树结构 */
  353. function getDeptTree() {
  354. listAttDataDevCat({
  355. projectId: userStore.projectId,
  356. projectCode: userStore.projectCode,
  357. validFlag: true
  358. }).then((response) => {
  359. deptOptions.value = proxy.handleTree(response.data, "id", "parentId");
  360. deptOptions.value = [
  361. {
  362. name: "数据开发类目",
  363. value: "",
  364. id: 0,
  365. children: deptOptions.value,
  366. },
  367. ];
  368. });
  369. deptUserTree().then((res) => {
  370. userList.value = res.data;
  371. });
  372. }
  373. function handleNodeClick(data) {
  374. queryParams.value.catCode = data.code;
  375. queryParams.value.pageNum = 1;
  376. handleQuery();
  377. }
  378. const route = useRoute();
  379. let openCron = ref(false);
  380. const dppEtlTaskList = ref([]);
  381. let row = ref();
  382. let expression = ref("");
  383. /** 运行实例按钮操作 */
  384. function handleJobLog(data) {
  385. row.value = "";
  386. row.value = data || "";
  387. openCron.value = true;
  388. expression.value = data.cronExpression || "";
  389. console.log("🚀 ~ handleJobLog ~ expression.value:", expression.value);
  390. }
  391. function handleschedulerState(id, row, e) {
  392. const text = row.schedulerState == "1" ? "上线" : "下线";
  393. // 弹出确认框
  394. proxy.$modal
  395. .confirm('确认要"' + text + '","' + row.name + '"数据开发调度状态吗?')
  396. .then(function () {
  397. loading.value = true;
  398. // 调用后台接口更新调度状态
  399. updateReleaseSchedule({
  400. id,
  401. schedulerState: row.schedulerState,
  402. projectCode: userStore.projectCode || "133545087166112",
  403. projectId: userStore.projectId,
  404. })
  405. .then((response) => {
  406. proxy.$modal.msgSuccess("操作成功");
  407. })
  408. .catch((error) => {
  409. // 处理失败时的恢复操作
  410. row.schedulerState = row.schedulerState === "1" ? "0" : "1"; // 恢复之前的状态
  411. })
  412. .finally(() => {
  413. loading.value = false; // 无论成功失败都停止加载
  414. });
  415. })
  416. .catch((error) => {
  417. // 失败时恢复状态
  418. row.schedulerState = row.schedulerState == "1" ? "0" : "1";
  419. });
  420. }
  421. /** 改变启用状态值 */
  422. function handleStatusChange(id, row, e) {
  423. const text = row.status == "1" ? "上线" : "下线";
  424. // 弹出确认框
  425. proxy.$modal
  426. .confirm('确认要"' + text + '","' + row.name + '"数据开发任务吗?')
  427. .then(function () {
  428. loading.value = true; // 开始加载
  429. // 调用后台接口更新发布状态
  430. updateReleaseJobTask({
  431. id,
  432. releaseState: row.status,
  433. projectCode: userStore.projectCode || "133545087166112",
  434. projectId: userStore.projectId,
  435. })
  436. .then((response) => {
  437. proxy.$modal.msgSuccess("操作成功");
  438. })
  439. .catch((error) => {
  440. // 失败时恢复状态
  441. row.status = row.status === "1" ? "0" : "1";
  442. })
  443. .finally(() => {
  444. loading.value = false; // 无论成功失败都停止加载
  445. });
  446. })
  447. .catch((error) => {
  448. // 失败时恢复状态
  449. row.status = row.status === "1" ? "0" : "1";
  450. });
  451. }
  452. /** 确定后回传值 */
  453. function crontabFill(value) {
  454. row.value.crontab = value;
  455. releaseTaskCrontab({
  456. crontab: row.value.crontab,
  457. projectCode: userStore.projectCode || "133545087166112",
  458. projectId: userStore.projectId,
  459. id: row.value.id,
  460. }).then((response) => {
  461. proxy.$modal.msgSuccess("操作成功");
  462. getList();
  463. });
  464. }
  465. const handleExecuteOnce = async (row) => {
  466. if (!row?.id) {
  467. proxy.$modal.msgWarning("无效的任务id,请刷新后重试");
  468. return;
  469. }
  470. loading.value = true;
  471. try {
  472. const res = await startDppEtlTask(row.id);
  473. if (Number(res?.code) === 200) {
  474. proxy.$modal.msgSuccess("执行成功");
  475. } else {
  476. proxy.$modal.msgWarning(res?.msg || "执行失败,请联系管理员");
  477. }
  478. } finally {
  479. setTimeout(() => {
  480. loading.value = false;
  481. getList();
  482. }, 1000);
  483. }
  484. };
  485. const handleExecuteStop = async (row) => {
  486. if (!row?.taskInstanceId) {
  487. proxy.$modal.msgWarning("当前任务无法停止,请刷新后重试");
  488. return;
  489. }
  490. loading.value = true;
  491. try {
  492. const res = await execute(row.taskInstanceId, 'STOP');
  493. if (Number(res?.code) === 200) {
  494. proxy.$modal.msgSuccess("执行成功");
  495. } else {
  496. proxy.$modal.msgWarning(res?.msg || "执行失败,请联系管理员");
  497. }
  498. } finally {
  499. setTimeout(() => {
  500. loading.value = false;
  501. getList();
  502. }, 2000);
  503. }
  504. };
  505. let DataView = ref(false);
  506. /** 运行实例接口 */
  507. function handleDataView(row) {
  508. form.value = row;
  509. DataView.value = true;
  510. }
  511. // 列显隐信息
  512. const columns = ref([
  513. { key: 0, label: "编号", visible: true },
  514. { key: 1, label: "任务名称", visible: true },
  515. { key: 4, label: "任务类目", visible: true },
  516. { key: 3, label: "执行引擎", visible: true },
  517. { key: 2, label: "描述", visible: true },
  518. { key: 7, label: "任务状态", visible: true },
  519. { key: 8, label: "调度状态", visible: true },
  520. { key: 9, label: "执行策略", visible: true },
  521. { key: 5, label: "处理类型", visible: true },
  522. { key: 13, label: "调度周期", visible: true },
  523. { key: 14, label: "最近运行时间", visible: true },
  524. { key: 10, label: "创建人", visible: true },
  525. { key: 11, label: "创建时间", visible: true },
  526. { key: 6, label: "配置状态", visible: true },
  527. ]);
  528. const getColumnVisibility = (key) => {
  529. const column = columns.value.find((col) => col.key === key);
  530. // 如果没有找到对应列配置,默认显示
  531. if (!column) return true;
  532. // 如果找到对应列配置,根据visible属性来控制显示
  533. return column.visible;
  534. };
  535. const open = ref(false);
  536. const loading = ref(false);
  537. const showSearch = ref(true);
  538. const ids = ref([]);
  539. const total = ref(0);
  540. const defaultSort = ref({ prop: "createTime", order: "desc" });
  541. const router = useRouter();
  542. const data = reactive({
  543. form: {
  544. id: "",
  545. code: "", // 组件的 code
  546. taskType: "",
  547. name: "name", // 名字
  548. version: "", // 版本号
  549. componentType: "",
  550. type: "3",
  551. taskConfig: {
  552. name: "",
  553. catCode: "",
  554. personCharge: "",
  555. contactNumber: "",
  556. releaseState: "0",
  557. description: "",
  558. },
  559. taskParams: {
  560. sqlType: "1",
  561. type: "",
  562. sql: "",
  563. typaCode: "DM", // 默认值
  564. localParams: [],
  565. datasources: {
  566. datasourceId: "", // 默认值
  567. datasourceType: "",
  568. dbname: "",
  569. },
  570. },
  571. },
  572. queryParams: {
  573. pageNum: 1,
  574. pageSize: 10,
  575. name: null,
  576. status: null,
  577. type: 3,
  578. orderByColumn: "create_time",
  579. isAsc: "desc",
  580. },
  581. rules: {},
  582. });
  583. const { queryParams, form, rules } = toRefs(data);
  584. // 监听 id 变化
  585. watch(
  586. () => userStore.projectCode,
  587. (newId) => {
  588. getList();
  589. },
  590. { immediate: true } // `immediate` 为 true 表示页面加载时也会立即执行一次 watch
  591. );
  592. /** 查询数据开发任务列表 */
  593. function getList() {
  594. loading.value = true;
  595. queryParams.value.projectCode = userStore.projectCode;
  596. queryParams.value.projectId = userStore.projectId;
  597. listDppEtlTask(queryParams.value).then((response) => {
  598. dppEtlTaskList.value = response.data.rows;
  599. dppEtlTaskList.value = response.data.rows.map(item => ({
  600. ...item,
  601. executionTypeObj: getExecutionType(item.datasourceType)
  602. }));
  603. total.value = response.data.total;
  604. loading.value = false;
  605. });
  606. }
  607. // 表单重置
  608. function reset() {
  609. form.value = {
  610. id: null,
  611. type: null,
  612. name: null,
  613. status: null,
  614. };
  615. proxy.resetForm("dppEtlTaskRef");
  616. }
  617. /** 搜索按钮操作 */
  618. function handleQuery() {
  619. queryParams.value.pageNum = 1;
  620. getList();
  621. }
  622. const DeptTreeRef = ref(null);
  623. /** 重置按钮操作 */
  624. function resetQuery() {
  625. if (DeptTreeRef.value?.resetTree) {
  626. DeptTreeRef.value.resetTree();
  627. }
  628. queryParams.value.catCode = "";
  629. queryParams.value.pageNum = 1;
  630. proxy.resetForm("queryRef");
  631. handleQuery();
  632. }
  633. /** 提交按钮 */
  634. function submitForm() {
  635. proxy.$refs["dppEtlTaskRef"].validate((valid) => {
  636. if (valid) {
  637. if (form.value.id != null) {
  638. updateDppEtlTask(form.value)
  639. .then((response) => {
  640. proxy.$modal.msgSuccess("修改成功");
  641. open.value = false;
  642. getList();
  643. })
  644. .catch((error) => { });
  645. } else {
  646. addDppEtlTask(form.value)
  647. .then((response) => {
  648. proxy.$modal.msgSuccess("新增成功");
  649. open.value = false;
  650. getList();
  651. })
  652. .catch((error) => { });
  653. }
  654. }
  655. });
  656. }
  657. /** 删除按钮操作 */
  658. function handleDelete(row) {
  659. const _ids = row.id || ids.value;
  660. proxy.$modal
  661. .confirm('是否确认删除数据开发任务编号为"' + _ids + '"的数据项?')
  662. .then(function () {
  663. return delDppEtlTask(_ids);
  664. })
  665. .then(() => {
  666. getList();
  667. proxy.$modal.msgSuccess("删除成功");
  668. })
  669. .catch(() => { });
  670. }
  671. function routeTo(link, row) {
  672. if (link !== "" && link.indexOf("http") !== -1) {
  673. window.location.href = link;
  674. return;
  675. }
  676. if (link !== "") {
  677. if (link === router.currentRoute.value.path) {
  678. window.location.reload();
  679. } else {
  680. router.push({
  681. path: link,
  682. query: {
  683. id: row.id,
  684. info: row.info,
  685. },
  686. });
  687. }
  688. }
  689. }
  690. const cleanupThirdPartyResources = () => {
  691. // 检查并清理可能需要手动释放的资源
  692. if (window.someChartInstance && typeof window.someChartInstance.dispose === 'function') {
  693. window.someChartInstance.dispose();
  694. }
  695. };
  696. onUnmounted(() => {
  697. // 清理可能的第三方库资源
  698. cleanupThirdPartyResources();
  699. });
  700. onActivated(() => {
  701. const from = router.options.history.state.back || "";
  702. getList();
  703. });
  704. getDeptTree();
  705. </script>
  706. <style scoped lang="scss">
  707. ::v-deep {
  708. .selectlist .el-tag.el-tag--info {
  709. background: #f3f8ff !important;
  710. border: 0px solid #6ba7ff !important;
  711. color: #2666fb !important;
  712. }
  713. }
  714. .el-main {
  715. padding: 2px 0px;
  716. // box-shadow: 1px 1px 3px rgba(0, 0, 0, .2);
  717. }
  718. //上传附件样式调整
  719. ::v-deep {
  720. // .el-upload-list{
  721. // display: flex;
  722. // }
  723. .el-upload-list__item {
  724. width: 100%;
  725. height: 25px;
  726. }
  727. }
  728. </style>