Files
fad_oa/ruoyi-ui/src/views/oa/task/allocation/index.vue
2026-06-16 15:13:51 +08:00

1052 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryFormProject" size="small" :inline="true" label-width="90px">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable />
</el-form-item>
<el-form-item label="项目编号" prop="projectNum">
<el-input v-model="queryParams.projectNum" placeholder="请输入项目编号" clearable />
</el-form-item>
<el-form-item label="项目代号" prop="projectCode">
<el-input v-model="queryParams.projectCode" placeholder="请输入项目代号" clearable />
</el-form-item>
<el-form-item label="发起人姓名" prop="createUserNickName">
<el-input v-model="queryParams.createUserNickName" placeholder="请输入发起人姓名" clearable />
</el-form-item>
<el-form-item label="执行人姓名" prop="createUserNickName">
<el-input v-model="queryParams.workerNickName" placeholder="请输入执行人姓名" clearable />
</el-form-item>
<el-form-item label="日期范围">
<el-date-picker v-model="queryParams.searchTime" type="daterange" value-format="yyyy-MM-dd"
start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增任务
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">删除
</el-button>
</el-col>
</el-row>
<el-alert type="info">
<span @click="gotoPurchase" style="cursor: pointer;">如要发放采购相关需求请移步采购需求管理(点击此处快速跳转)</span>
</el-alert>
<el-row :gutter="10" v-loading="loading">
<el-col class="task-col" v-for="item in taskList" :key="item.taskId">
<el-card class="task-card" shadow="hover" @click.native="handleLookTask(item)">
<!-- 卡片头部 -->
<template slot="header">
<div class="card-header">
<!-- 第一行任务标题和优先级 -->
<div class="header-row">
<div class="task-title">{{ item.taskTitle }}</div>
<div class="task-priority">
<el-tag v-if="item.taskGrade === '2'" type="danger">紧急</el-tag>
<el-tag v-else-if="item.taskGrade === '1'" type="warning">中等</el-tag>
<el-tag v-else-if="item.taskGrade === '0'" type="info">一般</el-tag>
</div>
</div>
<!-- 第二行任务状态和任务时间 -->
<div class="header-row">
<div class="task-status">
<el-tag v-if="item.state === 2" type="success">执行完成</el-tag>
<el-tag v-else-if="item.state === 1" type="warning">待验收</el-tag>
<el-tag v-else-if="item.overDays > 0" type="danger">逾期{{ Math.abs(item.overDays) }}</el-tag>
<el-tag v-else type="info">剩余{{ Math.abs(item.overDays) }}</el-tag>
</div>
<div class="task-time">
<el-tag type="info" size="small">{{ parseTime(item.beginTime, '{y}-{m}-{d}') }} {{
parseTime(item.finishTime, '{y}-{m}-{d}') }}</el-tag>
</div>
</div>
</div>
</template>
<!-- 卡片内容 -->
<div class="card-content">
<!-- 项目信息 -->
<div class="info-item">
<span class="info-label">项目名称</span>
<el-tag v-if="item.projectName === null" type="info">未关联项目</el-tag>
<span v-else>{{ item.projectName }}</span>
</div>
<div class="info-item">
<span class="info-label">项目代号</span>
<el-tag v-if="item.projectCode == null" type="info"></el-tag>
<el-tag v-else type="primary">{{ item.projectCode }}</el-tag>
</div>
<!-- 任务信息 -->
<div class="info-item">
<span class="info-label">发起人</span>
<span>{{ item.createUserNickName }}</span>
</div>
<div class="info-item">
<span class="info-label">执行人</span>
<div v-if="item.workerId === null">
<el-button type="text" size="mini" @click="visible = true">点击发放任务</el-button>
</div>
<span v-else>{{ item.workerNickName }}</span>
</div>
<div class="info-item attachment-row" @click.stop>
<span class="info-label">附件</span>
<file-preview v-if="item.accessory" :value="item.accessory" class="card-attachment" />
<el-tag v-else type="info" size="mini">无附件</el-tag>
</div>
</div>
<!-- 卡片底部操作按钮 -->
<div class="card-footer">
<el-button size="mini" type="text" v-if="item.taskRank === 0" icon="el-icon-copy-document"
@click.stop="handleRank(item, 1)">置顶</el-button>
<el-button size="mini" type="text" v-if="item.taskRank === 1" icon="el-icon-copy-document"
@click.stop="handleRank(item, 0)">取消置顶</el-button>
<el-button size="mini" type="text" icon="el-icon-copy-document"
@click.stop="handleUpdate(item)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(item)">删除</el-button>
<el-button size="mini" type="text" icon="el-icon-s-order" @click.stop="handleOpLog(item)">操作历史</el-button>
</div>
</el-card>
</el-col>
</el-row>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 添加或修改任务管理对话框 -->
<el-dialog :title="title" :visible.sync="open" width="70%" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="110px">
<el-row>
<el-row>
<el-col :span="16">
<el-form-item label="任务主题" prop="taskTitle">
<el-input v-model="form.taskTitle" placeholder="请输入任务主题" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="工作类型" prop="taskType">
<el-select v-model="form.taskType" placeholder="请选择工作类型">
<el-option v-for="dict in dict.type.sys_work_type" :key="dict.value" :label="dict.label"
:value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-col :span="16">
<el-form-item label="任务时间">
<el-col :span="11">
<el-form-item prop="beginTime">
<el-date-picker clearable v-model="form.beginTime" type="datetime" value-format="yyyy-MM-dd hh:mm:ss"
placeholder="请选择开始时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="2" v-if="form.status === 0"></el-col>
<el-col :span="11">
<el-form-item prop="finishTime" v-if="form.status === 0">
<el-date-picker clearable v-model="form.finishTime" type="datetime" value-format="yyyy-MM-dd hh:mm:ss"
placeholder="请选择结束时间">
</el-date-picker>
</el-form-item>
</el-col>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="优先级" prop="taskGrade">
<el-radio-group v-model="form.taskGrade">
<el-radio v-for="dict in dict.type.sys_sort_grade" :key="dict.value" :label="dict.value">{{ dict.label
}}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="关联项目" prop="projectId">
<project-select v-model="form.projectId" style="width: 100%;" adjustable />
</el-form-item>
</el-col>
<el-col :span="12" v-loading="trackLoading">
<el-form-item label="项目进度" prop="trackId">
<el-cascader v-if="trackOptions" v-model="form.trackId" :options="trackOptions" :props="cascaderProps"
style="width: 100%;" placeholder="请选择" clearable></el-cascader>
<div v-else>该项目未设置项目进度或未选择项目</div>
<!-- <track-select v-model="form.trackId" style="width: 100%;" /> -->
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="执行人" prop="workerIds">
<div style="display: flex; align-items: center;">
<el-tooltip content="请选择执行人, 多选执行人后第一个指定人会作为负责人,其他被选中的人员作为协助者" placement="top">
<el-icon class="el-icon-question"></el-icon>
</el-tooltip>
<user-select v-model="form.workerIds" :disabled="!!form.taskId" />
</div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="详细描述">
<editor v-model="form.content" :min-height="192" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件" prop="accessory">
<file-upload v-model="form.accessory" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 操作历史抽屉 -->
<operation-log-drawer
:visible.sync="opLogDrawer"
:target-type="3"
:target-id="opLogTargetId"
:title="opLogTitle"
/>
<!--查看弹出层-->
<el-dialog title="任务详情" :visible.sync="openLook" width="70%" center>
<div class="task-detail-container">
<el-descriptions class="task-descriptions" :column="2" border>
<!-- 基本信息 -->
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-user"></i>
任务主题
</template>
<span class="task-title">{{ form.taskTitle }}</span>
</el-descriptions-item>
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
工作类型
</template>
<dict-tag :options="dict.type.sys_work_type" :value="form.taskType" />
</el-descriptions-item>
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
优先级
</template>
<dict-tag :options="dict.type.sys_sort_grade" :value="form.taskGrade" />
</el-descriptions-item>
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
任务状态
</template>
<el-tag v-if="form.state === 2" type="success">执行完成</el-tag>
<el-tag v-else-if="form.state === 1" type="warning">待验收</el-tag>
<el-tag v-else-if="form.overDays > 0" type="danger">逾期{{ Math.abs(form.overDays) }}</el-tag>
<el-tag v-else type="info">剩余{{ Math.abs(form.overDays) }}</el-tag>
</el-descriptions-item>
<!-- 项目信息 -->
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
项目名称
</template>
<span>{{ form.projectName || '未关联项目' }}</span>
</el-descriptions-item>
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
项目代号
</template>
<el-tag v-if="form.projectCode" type="primary">{{ form.projectCode }}</el-tag>
<el-tag v-else type="info"></el-tag>
</el-descriptions-item>
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
项目进度
</template>
<span>{{ form.secondLevelNode ? form.tabNode + ' / ' + form.firstLevelNode + ' / ' + form.secondLevelNode :
'-'
}}</span>
</el-descriptions-item>
<!-- 人员信息 -->
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
发起人
</template>
<span>{{ form.createUserNickName }}</span>
</el-descriptions-item>
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
执行人
</template>
<span>{{ form.workerNickName || '未分配' }}</span>
</el-descriptions-item>
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
协同人员
</template>
<span>{{ form.collaborator || '无' }}</span>
</el-descriptions-item>
<!-- 时间信息 -->
<el-descriptions-item :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
任务时间
</template>
<span>{{ parseTime(form.beginTime, '{y}-{m}-{d}') }} {{ parseTime(form.finishTime, '{y}-{m}-{d}')
}}</span>
</el-descriptions-item>
<!-- 详细内容 -->
<el-descriptions-item span="2" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
工作内容
</template>
<div class="content-box">
<div v-if="form.content" v-html="form.content"></div>
<div v-else class="empty-content">暂无工作内容</div>
</div>
</el-descriptions-item>
<el-descriptions-item span="2" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
备注
</template>
<div class="content-box">
<div v-if="form.remark" v-html="form.remark"></div>
<div v-else class="empty-content">暂无备注</div>
</div>
</el-descriptions-item>
<el-descriptions-item span="2" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
附件
</template>
<div class="attachment-box">
<file-preview v-if="form.accessory" v-model="form.accessory" />
<div v-else class="no-attachment">暂无附件...</div>
</div>
</el-descriptions-item>
</el-descriptions>
</div>
</el-dialog>
</div>
</template>
<script>
import { listProjectSchedule } from "@/api/oa/projectSchedule";
import { listPage } from "@/api/oa/projectScheduleStep";
import { addTask, delTask, getTask, listTask, updateTask } from "@/api/oa/task";
import { deptTreeSelect, selectUser } from "@/api/system/user";
import UserSelect from "@/components/UserSelect";
import ProjectSelect from "@/components/fad-service/ProjectSelect";
import FilePreview from "@/components/FilePreview";
import OperationLogDrawer from "@/views/oa/project/operationLog/OperationLogDrawer.vue";
export default {
name: "Task",
components: {
UserSelect,
ProjectSelect,
FilePreview,
OperationLogDrawer
},
dicts: ['sys_project_type', 'sys_project_status', 'sys_work_type', 'sys_sort_grade'],
data () {
return {
//项目id
projectId: '',
projectName: '',
// 项目总条数
total: 0,
taskTotal: 0,
deptName: null,
// 遮罩层
loading: true,
//搜索日期范围
searchTime: [],
//任务弹出层标题
titleDialog: '',
//任务管理弹出层
taskDialog: false,
visible: false,
// 任务管理表格数据
taskList: [],
deptProps: {
children: "children",
label: "label"
},
//任务表单
form: {},
// 按钮loading
buttonLoading: false,
// 任务修改弹出层
open: false,
//查看弹出层
openLook: false,
//附件
fileList: [],
//详情lable背景
lableBg: "background: #f0f9eb; width:150px; text-align: center;",
//任务弹出层标题
title: '',
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
searchTime: [],
},
userList: [],
// 非多个禁用
multiple: true,
userMultipleSelection: [],
deptOptions: [],
userParams: {
pageNum: 1,
pageSize: 10,
},
userLoading: false,
copyUser: [],
rules: {
workerIds: [
{ required: true, message: "任务执行者不能为空", trigger: "blur" },
],
},
trackOptions: null,
cascaderProps: {
checkStrictly: false, // 严格检查模式(父子节点不关联)
label: 'label', // 显示的文本字段
value: 'value', // 实际的值字段
children: 'children', // 子节点字段
// 判断是否禁用(前两级禁用,第三级启用)
disabled: (data) => {
// 第三级没有children以此判断层级
return !!data.children;
}
},
trackLoading: false,
// 操作历史抽屉
opLogDrawer: false,
opLogTargetId: null,
opLogTitle: ''
};
},
created () {
this.getList();
this.getTreeSelect();
this.getUserList();
},
watch: {
'form.projectId': {
handler (val) {
this.form.trackId = undefined;
if (val) {
this.trackLoading = true;
listProjectSchedule({ projectId: val })
.then(res => {
if (res.rows && res.rows.length > 0) {
// 有数据返回scheduleId继续执行
return res.rows[0].scheduleId;
} else {
// 无数据设置trackOptions并返回拒绝状态的Promise阻止后续执行
this.trackOptions = null;
this.trackLoading = false; // 这里也要停止加载状态
return Promise.reject('无项目计划数据'); // 关键:拒绝后续执行
}
})
.then(scheduleId => {
if (scheduleId) {
// 有scheduleId继续调用listPage
return listPage({ scheduleId: scheduleId, pageSize: 9999, pageNum: 1 });
} else {
// 无scheduleId返回拒绝状态的Promise
this.trackLoading = false;
return Promise.reject('无有效的scheduleId');
}
})
.then(res => {
// 只有前面都成功,才会执行到这里
this.trackOptions = this.convertToCascader(res.rows);
this.trackLoading = false;
})
.catch(err => {
// 捕获前面所有的拒绝状态,避免控制台报错(可选,根据需要处理错误)
console.log('流程终止:', err);
// 确保加载状态关闭(兜底)
this.trackLoading = false;
});
}
}
}
},
methods: {
// 转换数据为级联选择器格式
convertToCascader (rows) {
if (!rows || !rows.length) return [];
// 第一级分组按tabNode
const firstLevelMap = new Map();
rows.forEach(item => {
const tabNode = item.tabNode;
if (!firstLevelMap.has(tabNode)) {
firstLevelMap.set(tabNode, {
label: tabNode,
value: tabNode, // 第一级值可用tabNode非必须因不可选
children: []
});
}
// 第二级分组按firstLevelNode
const firstLevelItem = firstLevelMap.get(tabNode);
const secondLevelMap = new Map();
firstLevelItem.children.forEach(secondItem => {
secondLevelMap.set(secondItem.label, secondItem);
});
const firstLevelNode = item.firstLevelNode;
if (!secondLevelMap.has(firstLevelNode)) {
const secondLevelItem = {
label: firstLevelNode,
value: firstLevelNode, // 第二级值可用firstLevelNode非必须因不可选
children: []
};
firstLevelItem.children.push(secondLevelItem);
secondLevelMap.set(firstLevelNode, secondLevelItem);
}
// 第三级secondLevelNode可选项
const secondLevelItem = secondLevelMap.get(firstLevelNode);
secondLevelItem.children.push({
label: item.secondLevelNode,
value: item.trackId, // 第三级值为trackId
children: null // 标记为第三级无children
});
});
// 转换为数组格式
return Array.from(firstLevelMap.values());
},
gotoPurchase () {
this.$router.push({ path: '/hint/requirement' });
},
// 单选矿变化
handChange () {
if (this.form.status === 1) {
this.form.timeGap = 3
} else {
this.form.timeGap = null;
}
},
handleClose (tag) {
let userObj = this.userMultipleSelection.find(item => item.userId === tag.id);
this.userMultipleSelection.splice(this.userMultipleSelection.indexOf(userObj), 1);
this.copyUser = this.userMultipleSelection;
// 设置抄送人ID
if (this.copyUser && this.copyUser.length > 0) {
const val = this.copyUser.map(item => item.id);
this.form.workerIds = val instanceof Array ? val.join(',') : val;
} else {
this.form.workerIds = '';
}
},
submitUserData () {
this.visible = false;
if (!this.userMultipleSelection || this.userMultipleSelection.length <= 0) {
this.$modal.msgError("请选择用户");
return false;
}
let userIds = this.userMultipleSelection.map(k => k.userId);
this.copyUser = this.userMultipleSelection;
this.form.workerIds = userIds instanceof Array ? userIds.join(',') : userIds;
this.form.workerId = userIds instanceof Array ? userIds.join(',') : userIds;
},
changeCurrentUser (val) {
this.currentUserId = val.userId
},
handleSelectionChange (selection) {
this.userMultipleSelection = selection
},
// 节点单击事件
handleNodeClick (data) {
this.userParams.deptId = data.id;
this.getUserList();
},
filterNode (value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
/** 查询部门下拉树结构 */
getTreeSelect () {
deptTreeSelect().then(response => {
this.deptOptions = response.data;
});
},
getUserList () {
this.userLoading = true
selectUser(this.userParams).then(response => {
this.userList = response.rows;
this.userLoading = false;
});
},
/** 查询项目管理列表 */
getList () {
this.loading = true;
const payload = {
...this.queryParams,
taskId:this.$route.query.taskId!=null?this.$route.query.taskId:null,
beginTime: this.queryParams.searchTime[0] ? this.queryParams.searchTime[0] + ' 00:00:00' : undefined,
finishTime: this.queryParams.searchTime[1] ? this.queryParams.searchTime[1] + ' 23:59:59' : undefined
}
listTask(payload).then(response => {
this.taskList = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 任务搜索按钮操作 */
handleQuery () {
this.queryParams.pageNum = 1;
this.getList();
},
/**查看任务**/
handleLookTask (row) {
this.loading = true;
this.reset();
const taskId = row.taskId || this.ids
getTask(taskId).then(response => {
this.loading = false;
this.form = response.data;
// this.getFile(response.data.accessory)
this.openLook = true;
this.title = "查看任务";
});
},
/** 处理置顶 */
handleRank (row, rank) {
this.loading = true;
row.taskRank = rank;
updateTask(row).then(response => {
this.$modal.msgSuccess("操作成功")
this.getList();
})
},
/** 修改按钮操作 */
handleUpdate (row) {
this.loading = true;
this.reset();
const taskId = row.taskId || this.ids
getTask(taskId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改任务";
});
},
handleAdd () {
this.reset();
this.open = true;
this.title = "新增任务";
},
// 取消按钮
cancel () {
this.open = false;
this.reset();
},
submitForm () {
const payload = {
...this.form,
trackId: this.form.trackId ? this.form.trackId[2] : undefined,
}
if (!this.form.taskId) {
const workers = this.form.workerIds.split(',')
payload.workerIds = workers[0]
payload.collaborator = workers.slice(1).length > 0 ? workers.slice(1).join(',') : ''
}
if (this.form.taskId) {
updateTask(payload).then(response => {
this.open = false;
this.getList();
this.$modal.msgSuccess("修改成功")
})
} else {
this.$refs["form"].validate(valid => {
if (valid) {
addTask(payload).then(response => {
this.open = false;
this.getList();
this.$modal.msgSuccess("添加成功")
})
}
})
}
},
// 表单重置
reset () {
this.form = {
status: 0
};
this.resetForm("form");
this.fileList = [];
},
handleOpLog (item) {
this.opLogTargetId = item.taskId
this.opLogTitle = '操作历史 — ' + (item.taskTitle || '任务')
this.opLogDrawer = true
},
/** 删除按钮操作 */
handleDelete (row) {
const taskIds = row.taskId || this.ids;
this.$modal.confirm('是否确认删除任务管理编号为"' + taskIds + '"的数据项?').then(() => {
this.loading = true;
return delTask(taskIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
},
}
</script>
<style scoped>
.task-col {
flex: 0 0 20%;
max-width: 20%;
}
.task-card {
margin-bottom: 12px;
height: 300px;
/* 固定卡片高度 */
display: flex;
flex-direction: column;
font-size: 12px;
}
.task-card >>> .el-card__header {
padding: 10px 12px;
}
.task-card >>> .el-card__body {
padding: 10px 12px;
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.task-card .task-title {
font-size: 13px;
}
.task-card .info-label {
font-size: 12px;
min-width: 56px;
}
.task-card .info-item {
margin-bottom: 6px;
}
.task-card .card-footer .el-button {
margin-right: 4px;
padding: 4px 2px;
font-size: 12px;
}
@media (max-width: 1366px) {
.task-col {
flex: 0 0 25%;
max-width: 25%;
}
}
@media (max-width: 992px) {
.task-col {
flex: 0 0 33.3333%;
max-width: 33.3333%;
}
}
@media (max-width: 768px) {
.task-col {
flex: 0 0 50%;
max-width: 50%;
}
}
@media (max-width: 480px) {
.task-col {
flex: 0 0 100%;
max-width: 100%;
}
}
.attachment-row {
align-items: flex-start;
}
.card-attachment {
flex: 1;
min-width: 0;
margin: 0;
}
.card-attachment >>> .el-upload-list__item {
margin: 0;
border: none;
padding: 0;
background: transparent;
line-height: 1.4;
}
.card-attachment >>> .el-upload-list__item:hover {
background: transparent;
}
.card-attachment >>> .ele-upload-list__item-content-action {
display: none;
}
.card-attachment >>> .el-upload-list__item:hover .ele-upload-list__item-content-action {
display: flex;
gap: 4px;
}
.card-attachment >>> .el-icon-document {
color: #409eff;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
}
.card-header {
width: 100%;
display: flex;
flex-direction: column;
gap: 10px;
}
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.task-title {
font-size: 16px;
font-weight: bold;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
margin-right: 10px;
}
.task-priority {
display: flex;
align-items: center;
}
.task-status {
display: flex;
align-items: center;
}
.task-time {
display: flex;
align-items: center;
}
.card-content {
padding: 10px 0;
flex: 1;
overflow-y: auto;
min-height: 0;
}
.info-item {
margin-bottom: 10px;
display: flex;
align-items: center;
flex-wrap: nowrap;
/* 禁止换行 */
}
.info-label {
color: #606266;
font-size: 14px;
margin-right: 5px;
min-width: 80px;
white-space: nowrap;
/* 禁止换行 */
}
.info-item span:not(.info-label) {
white-space: nowrap;
/* 禁止项目名称等内容换行 */
overflow: hidden;
/* 超出部分隐藏 */
text-overflow: ellipsis;
/* 显示省略号 */
flex: 1;
/* 占据剩余空间 */
}
.card-footer {
display: flex;
justify-content: flex-start;
/* 按钮左对齐 */
align-items: center;
border-top: 1px solid #ebeef5;
padding-top: 10px;
margin-top: 10px;
width: 100%;
}
.card-footer .el-button {
margin-right: 10px;
}
/* 响应式调整 */
@media (max-width: 768px) {
.task-card {
height: auto;
}
.header-row {
flex-direction: column;
align-items: flex-start;
gap: 5px;
}
.info-item {
flex-direction: column;
align-items: flex-start;
}
.info-label {
margin-bottom: 5px;
}
}
/* 任务详情弹窗样式 */
.task-detail-container {
padding: 10px;
}
.task-descriptions {
margin-bottom: 0;
}
.task-descriptions .el-descriptions__label {
font-weight: bold;
background-color: #f0f9eb;
text-align: center;
width: 120px;
}
.task-title {
font-size: 16px;
font-weight: bold;
color: #333;
}
.content-box {
padding: 10px;
background-color: #fafafa;
border-radius: 4px;
min-height: 100px;
line-height: 1.6;
}
.attachment-box {
padding: 10px;
background-color: #fafafa;
border-radius: 4px;
}
.attachment-item {
margin-bottom: 8px;
display: flex;
align-items: center;
}
.attachment-item i {
margin-right: 5px;
color: #409eff;
}
.no-attachment {
color: #909399;
text-align: center;
padding: 20px;
}
.dialog-footer {
text-align: center;
}
</style>