| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- <template>
- <div>
- <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
- <div v-show="showSearch" class="mb-[10px]">
- <el-card shadow="hover">
- <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="110px">
- <el-form-item :label="t('qc.task.search.taskName')" prop="name" style="width: 300px">
- <el-input v-model="queryParams.name" :placeholder="t('qc.task.search.taskNamePlaceholder')" clearable @keyup.enter="handleQuery" />
- </el-form-item>
- <el-form-item :label="t('qc.task.search.initiator')" prop="initiator" style="width: 300px">
- <el-input
- v-model="queryParams.initiator"
- :placeholder="t('qc.task.search.initiatorPlaceholder')"
- clearable
- @keyup.enter="handleQuery"
- />
- </el-form-item>
- <el-form-item :label="t('qc.task.search.projectId')" prop="projectId" style="width: 300px">
- <el-input
- v-model="queryParams.projectId"
- :placeholder="t('qc.task.search.projectIdPlaceholder')"
- clearable
- @keyup.enter="handleQuery"
- />
- </el-form-item>
- <el-form-item :label="t('qc.task.search.deadline')" style="width: 300px">
- <el-date-picker
- v-model="dateRangeDeadline"
- value-format="YYYY-MM-DD HH:mm:ss"
- type="daterange"
- :range-separator="t('qc.task.search.rangeSeparator')"
- :start-placeholder="t('qc.task.search.startDate')"
- :end-placeholder="t('qc.task.search.endDate')"
- :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
- />
- </el-form-item>
- <el-form-item :label="t('qc.task.search.createBy')" prop="createBy" style="width: 300px">
- <el-input v-model="queryParams.createBy" :placeholder="t('qc.task.search.createByPlaceholder')" clearable @keyup.enter="handleQuery" />
- </el-form-item>
- <el-form-item :label="t('qc.task.search.createTime')" style="width: 300px">
- <el-date-picker
- v-model="dateRangeCreateTime"
- value-format="YYYY-MM-DD HH:mm:ss"
- type="daterange"
- :range-separator="t('qc.task.search.rangeSeparator')"
- :start-placeholder="t('qc.task.search.startDate')"
- :end-placeholder="t('qc.task.search.endDate')"
- :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
- />
- </el-form-item>
- <el-form-item :label="t('qc.task.search.updateBy')" prop="updateBy" style="width: 300px">
- <el-input v-model="queryParams.updateBy" :placeholder="t('qc.task.search.updateByPlaceholder')" clearable @keyup.enter="handleQuery" />
- </el-form-item>
- <el-form-item :label="t('qc.task.search.updateTime')" style="width: 300px">
- <el-date-picker
- v-model="dateRangeUpdateTime"
- value-format="YYYY-MM-DD HH:mm:ss"
- type="daterange"
- :range-separator="t('qc.task.search.rangeSeparator')"
- :start-placeholder="t('qc.task.search.startDate')"
- :end-placeholder="t('qc.task.search.endDate')"
- :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="Search" @click="handleQuery">{{ t('qc.task.button.search') }}</el-button>
- <el-button icon="Refresh" @click="resetQuery">{{ t('qc.task.button.reset') }}</el-button>
- </el-form-item>
- </el-form>
- </el-card>
- </div>
- </transition>
- <el-card shadow="never">
- <template #header>
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['qc:task:add']">{{ t('qc.task.button.add') }}</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['qc:task:remove']">{{
- t('qc.task.button.delete')
- }}</el-button>
- </el-col>
- <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
- </template>
- <el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column :label="t('qc.task.table.index')" align="center" prop="id" v-if="true" />
- <el-table-column :label="t('qc.task.table.taskName')" align="center" prop="name" width="200" />
- <el-table-column :label="t('qc.task.table.initiator')" align="center" prop="initiator" width="150">
- <template #default="scope">
- <span>{{ scope.row.initiatorName || scope.row.initiator }}</span>
- </template>
- </el-table-column>
- <el-table-column :label="t('qc.task.table.projectId')" align="center" prop="projectId" width="200">
- <template #default="scope">
- <span>{{ scope.row.projectName || scope.row.projectId }}</span>
- </template>
- </el-table-column>
- <el-table-column :label="t('qc.task.table.deadline')" align="center" prop="deadline" width="180">
- <template #default="scope">
- <span>{{ parseTime(scope.row.deadline, '{y}-{m}-{d}') }}</span>
- </template>
- </el-table-column>
- <el-table-column :label="t('qc.task.table.status')" align="center" prop="status" width="100">
- <template #default="scope">
- <el-tag v-if="scope.row.status === 0" type="info">{{ t('qc.task.status.notStarted') }}</el-tag>
- <el-tag v-else-if="scope.row.status === 1" type="warning">{{ t('qc.task.status.inProgress') }}</el-tag>
- <el-tag v-else-if="scope.row.status === 2" type="success">{{ t('qc.task.status.completed') }}</el-tag>
- <el-tag v-else type="info">{{ t('qc.task.status.unknown') }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column :label="t('qc.task.table.completion')" align="center" width="200">
- <template #default="scope">
- <div style="width: 100%; padding: 5px 0">
- <el-progress
- :percentage="Math.round((Number(scope.row.schedule) || 0) * 100 * 100) / 100"
- :stroke-width="14"
- :show-text="true"
- :format="(percentage) => `${percentage}%`"
- :empty-color="'#e0e0e0'"
- color="#409eff"
- style="width: 100%"
- />
- </div>
- </template>
- </el-table-column>
- <el-table-column :label="t('qc.task.table.note')" align="center" prop="note" />
- <el-table-column :label="t('qc.task.table.createBy')" align="center" prop="createBy" width="150" />
- <el-table-column :label="t('qc.task.table.createTime')" align="center" prop="createTime" width="180" />
- <el-table-column :label="t('qc.task.table.updateBy')" align="center" prop="updateBy" width="150" />
- <el-table-column :label="t('qc.task.table.updateTime')" align="center" prop="updateTime" width="180" />
- <el-table-column :label="t('qc.task.table.action')" align="center" fixed="right" width="240" class-name="small-padding fixed-width">
- <template #default="scope">
- <el-button
- v-hasPermi="['qc:task:query']"
- type="info"
- icon="View"
- style="padding: 0 5px; font-size: 10px; height: 24px; margin-right: 5px"
- @click="handleView(scope.row.id)"
- >
- {{ t('qc.task.button.view') }}
- </el-button>
- <el-button
- v-if="scope.row.status === 0 && scope.row.initiator === userStore.userId"
- v-hasPermi="['qc:task:start']"
- type="primary"
- icon="VideoPlay"
- style="padding: 0 5px; font-size: 10px; height: 24px; margin-right: 5px"
- @click="handleStart(scope.row)"
- >
- {{ t('qc.task.button.start') }}
- </el-button>
- <el-button
- v-hasPermi="['qc:task:remove']"
- type="danger"
- icon="Delete"
- style="padding: 0 5px; font-size: 10px; height: 24px"
- @click="handleDelete(scope.row)"
- >
- {{ t('qc.task.button.delete') }}
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
- </el-card>
- <!-- 新增/编辑任务对话框 -->
- <el-dialog v-model="dialogVisible" :title="dialogTitle" width="900px" append-to-body @close="handleDialogClose">
- <el-form ref="taskFormRef" :model="taskForm" :rules="taskRules" label-width="160px">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item :label="t('qc.task.form.taskName')" prop="name">
- <el-input v-model="taskForm.name" :placeholder="t('qc.task.form.taskNamePlaceholder')" clearable />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item :label="t('qc.task.form.projectId')" prop="projectId">
- <el-select v-model="taskForm.projectId" :placeholder="t('qc.task.form.projectIdPlaceholder')" clearable filterable style="width: 100%">
- <el-option v-for="project in projectList" :key="project.id" :label="project.name" :value="project.id" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item :label="t('qc.task.form.deadline')" prop="deadline">
- <el-date-picker
- v-model="taskForm.deadline"
- type="date"
- :placeholder="t('qc.task.form.deadlinePlaceholder')"
- value-format="YYYY-MM-DD"
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item :label="t('qc.task.form.proportion')" prop="proportion">
- <el-input-number
- v-model="taskForm.proportion"
- :min="1"
- :max="100"
- :placeholder="t('qc.task.form.proportionPlaceholder')"
- style="width: 100%"
- />
- <span style="margin-left: 8px; color: #909399">{{ t('qc.task.form.proportionUnit') }}</span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="24">
- <el-form-item :label="t('qc.task.form.note')" prop="note">
- <el-input v-model="taskForm.note" type="textarea" :rows="3" :placeholder="t('qc.task.form.notePlaceholder')" />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="dialogVisible = false">{{ t('qc.task.button.cancel') }}</el-button>
- <el-button type="primary" @click="submitForm" :loading="submitLoading">{{ t('qc.task.button.confirm') }}</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup name="TaskList" lang="ts">
- import { listTask, getTask, delTask, startTask, addTask, updateTask } from '@/api/qc/task';
- import { TaskVO, TaskQuery, TaskForm } from '@/api/qc/task/types';
- import { listProject } from '@/api/document/folder';
- import { useUserStore } from '@/store/modules/user';
- import { useI18n } from 'vue-i18n';
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const { t } = useI18n();
- const userStore = useUserStore();
- const taskList = ref<TaskVO[]>([]);
- const loading = ref(true);
- const showSearch = ref(true);
- const ids = ref<Array<string | number>>([]);
- const single = ref(true);
- const multiple = ref(true);
- const total = ref(0);
- const dateRangeDeadline = ref<[DateModelType, DateModelType]>(['', '']);
- const dateRangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
- const dateRangeUpdateTime = ref<[DateModelType, DateModelType]>(['', '']);
- const queryFormRef = ref<ElFormInstance>();
- const taskFormRef = ref<ElFormInstance>();
- // 对话框相关
- const dialogVisible = ref(false);
- const dialogTitle = ref('');
- const submitLoading = ref(false);
- const projectList = ref<any[]>([]);
- // 表单数据
- const taskForm = ref<TaskForm>({
- id: undefined,
- name: undefined,
- initiator: undefined,
- projectId: undefined,
- proportion: undefined,
- deadline: undefined,
- status: 0,
- note: undefined
- });
- // 表单验证规则
- const taskRules = {
- name: [{ required: true, message: t('qc.task.rule.taskNameRequired'), trigger: 'blur' }],
- projectId: [{ required: true, message: t('qc.task.rule.projectIdRequired'), trigger: 'change' }],
- deadline: [{ required: true, message: t('qc.task.rule.deadlineRequired'), trigger: 'change' }],
- proportion: [{ required: true, message: t('qc.task.rule.proportionRequired'), trigger: 'blur' }]
- };
- const data = reactive<PageData<any, TaskQuery>>({
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- name: undefined,
- initiator: undefined,
- projectId: undefined,
- status: undefined,
- createBy: undefined,
- updateBy: undefined,
- params: {
- deadline: undefined,
- createTime: undefined,
- updateTime: undefined
- }
- }
- });
- const { queryParams } = toRefs(data);
- /** 查询文档质控任务列表 */
- const getList = async () => {
- loading.value = true;
- queryParams.value.params = {};
- proxy?.addDateRange(queryParams.value, dateRangeDeadline.value, 'Deadline');
- proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, 'CreateTime');
- proxy?.addDateRange(queryParams.value, dateRangeUpdateTime.value, 'UpdateTime');
- const res = await listTask(queryParams.value);
- taskList.value = res.rows;
- total.value = res.total;
- loading.value = false;
- };
- /** 搜索按钮操作 */
- const handleQuery = () => {
- queryParams.value.pageNum = 1;
- getList();
- };
- /** 重置按钮操作 */
- const resetQuery = () => {
- dateRangeDeadline.value = ['', ''];
- dateRangeCreateTime.value = ['', ''];
- dateRangeUpdateTime.value = ['', ''];
- queryFormRef.value?.resetFields();
- handleQuery();
- };
- /** 多选框选中数据 */
- const handleSelectionChange = (selection: TaskVO[]) => {
- ids.value = selection.map((item) => item.id);
- single.value = selection.length != 1;
- multiple.value = !selection.length;
- };
- /** 新增按钮操作 */
- const handleAdd = () => {
- resetForm();
- dialogTitle.value = t('qc.task.dialog.addTask');
- dialogVisible.value = true;
- loadProjectList();
- };
- /** 加载项目列表 */
- const loadProjectList = async () => {
- try {
- const res = await listProject({ pageNum: 1, pageSize: 1000 });
- projectList.value = res.rows || [];
- } catch (error) {
- console.error(t('qc.task.message.loadProjectFailed'), error);
- }
- };
- /** 重置表单 */
- const resetForm = () => {
- taskForm.value = {
- id: undefined,
- name: undefined,
- initiator: undefined,
- projectId: undefined,
- proportion: undefined,
- deadline: undefined,
- status: 0,
- note: undefined
- };
- taskFormRef.value?.resetFields();
- };
- /** 对话框关闭 */
- const handleDialogClose = () => {
- resetForm();
- };
- /** 提交表单 */
- const submitForm = async () => {
- if (!taskFormRef.value) return;
- await taskFormRef.value.validate(async (valid) => {
- if (valid) {
- submitLoading.value = true;
- try {
- // 设置发起人为当前登录用户
- const submitData = {
- ...taskForm.value,
- initiator: userStore.userId
- };
- if (submitData.id) {
- await updateTask(submitData);
- proxy?.$modal.msgSuccess(t('qc.task.message.editSuccess'));
- } else {
- await addTask(submitData);
- proxy?.$modal.msgSuccess(t('qc.task.message.addSuccess'));
- }
- dialogVisible.value = false;
- await getList();
- } catch (error) {
- console.error(t('qc.task.message.submitFailed'), error);
- } finally {
- submitLoading.value = false;
- }
- }
- });
- };
- /** 查看任务详情 */
- const handleView = (taskId: string | number) => {
- proxy?.$router.push({
- path: '/task/detail',
- query: { id: taskId }
- });
- };
- /** 开始任务 */
- const handleStart = async (row: TaskVO) => {
- try {
- await proxy?.$modal.confirm(t('qc.task.message.startConfirm', { name: row.name }));
- const res = await startTask(row.id);
- if (res.code === 200) {
- proxy?.$modal.msgSuccess(t('qc.task.message.startSuccess'));
- getList(); // 重新获取列表
- } else {
- proxy?.$modal.msgError(res.msg || t('qc.task.message.startFailed'));
- }
- } catch (error) {
- console.error(t('qc.task.message.startFailed'), error);
- }
- };
- /** 删除按钮操作 */
- const handleDelete = async (row?: TaskVO) => {
- const _ids = row?.id || ids.value;
- await proxy?.$modal.confirm(t('qc.task.message.deleteConfirm', { ids: _ids })).finally(() => (loading.value = false));
- await delTask(_ids);
- proxy?.$modal.msgSuccess(t('qc.task.message.deleteSuccess'));
- await getList();
- };
- onMounted(() => {
- getList();
- });
- </script>
|