1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168 |
- <template>
- <div class="repair-order-container">
- <!-- 页面标题 -->
- <div class="page-header">
- <h2 class="page-title">
- <el-icon><Tools /></el-icon>
- 维修工单管理
- </h2>
- <div class="header-actions">
- <!-- <el-button type="primary" :icon="Plus" @click="handleAdd" v-hasPermi="['repairOrder:repairOrder:add']">
- 新建工单
- </el-button>-->
- <el-button :icon="Download" @click="handleExport" v-hasPermi="['repairOrder:repairOrder:export']">
- 导出报表
- </el-button>
- </div>
- </div>
- <!-- 统计卡片 -->
- <el-row :gutter="20" class="statistics-cards">
- <el-col :xs="24" :sm="12" :md="6">
- <div class="stat-card">
- <div class="stat-icon blue">
- <el-icon><DocumentCopy /></el-icon>
- </div>
- <div class="stat-content">
- <div class="stat-value">{{ statistics.total }}</div>
- <div class="stat-label">工单总数</div>
- </div>
- </div>
- </el-col>
- <el-col :xs="24" :sm="12" :md="6">
- <div class="stat-card">
- <div class="stat-icon orange">
- <el-icon><Clock /></el-icon>
- </div>
- <div class="stat-content">
- <div class="stat-value">{{ statistics.pending }}</div>
- <div class="stat-label">待处理</div>
- </div>
- </div>
- </el-col>
- <el-col :xs="24" :sm="12" :md="6">
- <div class="stat-card">
- <div class="stat-icon purple">
- <el-icon><Loading /></el-icon>
- </div>
- <div class="stat-content">
- <div class="stat-value">{{ statistics.processing }}</div>
- <div class="stat-label">处理中</div>
- </div>
- </div>
- </el-col>
- <el-col :xs="24" :sm="12" :md="6">
- <div class="stat-card">
- <div class="stat-icon green">
- <el-icon><CircleCheck /></el-icon>
- </div>
- <div class="stat-content">
- <div class="stat-value">{{ statistics.completed }}</div>
- <div class="stat-label">已完成</div>
- </div>
- </div>
- </el-col>
- </el-row>
- <!-- 搜索栏 -->
- <el-card class="search-card" shadow="never">
- <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
- <el-row :gutter="20">
- <el-col :xs="24" :sm="12" :md="6">
- <el-form-item label="工单编号" prop="orderNo">
- <el-input
- v-model="queryParams.orderNo"
- placeholder="请输入工单编号"
- clearable
- :prefix-icon="Search"
- @keyup.enter="handleQuery"
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- <el-col :xs="24" :sm="12" :md="6">
- <el-form-item label="项目名称" prop="projectName">
- <el-input
- v-model="queryParams.projectName"
- placeholder="请输入项目名称"
- clearable
- :prefix-icon="Search"
- @keyup.enter="handleQuery"
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- <el-col :xs="24" :sm="12" :md="6">
- <el-form-item label="工单状态" prop="orderStatus">
- <el-select
- v-model="queryParams.orderStatus"
- placeholder="请选择工单状态"
- clearable
- style="width: 100%;min-width: 200px;"
- >
- <el-option
- v-for="dict in repair_status"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- >
- <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;">
- <span>{{ dict.label }}</span>
- <el-tag :type="getStatusTagType(dict.value)" size="small">
- {{ dict.label }}
- </el-tag>
- </div>
- </el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :xs="24" :sm="12" :md="6">
- <el-form-item label="派单时间" prop="dateRange">
- <el-date-picker
- v-model="queryParams.dateRange"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="24" style="text-align: right;">
- <el-form-item>
- <el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
- <el-button :icon="Refresh" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- </el-card>
- <!-- 数据表格 -->
- <el-card class="table-card" shadow="never">
- <div class="table-header">
- <span class="table-title">工单列表</span>
- <div class="table-tools">
- <el-tooltip content="刷新" placement="top">
- <el-button :icon="Refresh" circle size="small" @click="getList" />
- </el-tooltip>
- <el-tooltip content="显示/隐藏搜索" placement="top">
- <el-button
- :icon="showSearch ? View : Hide"
- circle
- size="small"
- @click="showSearch = !showSearch"
- />
- </el-tooltip>
- </div>
- </div>
- <el-table
- v-loading="loading"
- :data="repairOrderList"
- @selection-change="handleSelectionChange"
- stripe
- border
- :row-class-name="tableRowClassName"
- >
- <el-table-column type="selection" width="50" align="center" />
- <el-table-column label="序号" type="index" width="60" align="center">
- <template #default="scope">
- {{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}
- </template>
- </el-table-column>
- <el-table-column label="工单编号" align="center" prop="orderNo" min-width="120">
- <template #default="scope">
- <el-link type="primary" @click="showDetail(scope.row)">
- {{ scope.row.orderNo }}
- </el-link>
- </template>
- </el-table-column>
- <el-table-column label="工单内容" align="center" prop="orderContent" min-width="200" show-overflow-tooltip />
- <el-table-column label="项目名称" align="center" prop="projectName" min-width="150" show-overflow-tooltip />
- <el-table-column label="派单时间" align="center" prop="assignTime" width="180" sortable>
- <template #default="scope">
- <div class="time-info">
- <el-icon><Clock /></el-icon>
- <span>{{ parseTime(scope.row.assignTime, '{y}-{m}-{d} {h}:{i}') }}</span>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="责任人" align="center" prop="finishBy" min-width="100">
- <template #default="scope">
- <div class="user-info">
- <el-avatar size="small" :src="getUserAvatar(scope.row.finishBy)">
- {{ scope.row.finishBy?.charAt(0) || '无' }}
- </el-avatar>
- <span>{{ scope.row.finishBy || '未分配' }}</span>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="工单状态" align="center" prop="orderStatus" width="100">
- <template #default="scope">
- <el-tag
- :type="getStatusTagType(scope.row.orderStatus)"
- effect="dark"
- size="small"
- >
- <el-icon v-if="scope.row.orderStatus === '0'"><Clock /></el-icon>
- <el-icon v-else-if="scope.row.orderStatus === '1'"><Loading /></el-icon>
- <el-icon v-else-if="scope.row.orderStatus === '2'"><CircleCheck /></el-icon>
- {{ getStatusLabel(scope.row.orderStatus) }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="完成时间" align="center" prop="finishTime" width="180">
- <template #default="scope">
- <span v-if="scope.row.finishTime">
- {{ parseTime(scope.row.finishTime, '{y}-{m}-{d} {h}:{i}') }}
- </span>
- <span v-else class="text-muted">-</span>
- </template>
- </el-table-column>
- <el-table-column label="附件" align="center" prop="annex" width="80">
- <template #default="scope">
- <el-button
- v-if="scope.row.annex"
- type="primary"
- link
- :icon="Paperclip"
- @click="downloadFile(scope.row.annex)"
- >
- 查看
- </el-button>
- <span v-else class="text-muted">-</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200" fixed="right">
- <template #default="scope">
- <el-button
- link
- type="primary"
- :icon="View"
- @click="showDetail(scope.row)"
- v-hasPermi="['repairOrder:repairOrder:edit']"
- >
- 详情
- </el-button>
- <el-button
- v-if="scope.row.orderStatus === '0' || scope.row.orderStatus === '1'"
- link
- type="warning"
- :icon="Edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['repairOrder:repairOrder:edit']"
- >
- 处理
- </el-button>
- <el-button
- link
- type="danger"
- :icon="Delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['repairOrder:repairOrder:remove']"
- >
- 删除
- </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-drawer
- v-model="detailVisible"
- title="工单详情"
- direction="rtl"
- size="50%"
- class="detail-drawer"
- >
- <template #header>
- <div class="drawer-header">
- <h3>工单详情</h3>
- <el-tag :type="getStatusTagType(detailData.orderStatus)" size="large">
- {{ getStatusLabel(detailData.orderStatus) }}
- </el-tag>
- </div>
- </template>
- <div class="detail-content">
- <el-descriptions :column="2" border>
- <el-descriptions-item label="工单编号" :span="1">
- <span class="detail-value">{{ detailData.orderNo }}</span>
- </el-descriptions-item>
- <el-descriptions-item label="项目名称" :span="1">
- {{ detailData.projectName }}
- </el-descriptions-item>
- <el-descriptions-item label="工单内容" :span="2">
- {{ detailData.orderContent }}
- </el-descriptions-item>
- <el-descriptions-item label="派单时间">
- {{ parseTime(detailData.assignTime, '{y}-{m}-{d} {h}:{i}:{s}') }}
- </el-descriptions-item>
- <el-descriptions-item label="完成时间">
- {{ detailData.finishTime ? parseTime(detailData.finishTime, '{y}-{m}-{d} {h}:{i}:{s}') : '未完成' }}
- </el-descriptions-item>
- <el-descriptions-item label="责任人">
- <div class="user-info">
- <el-avatar size="small" :src="getUserAvatar(detailData.finishBy)">
- {{ detailData.finishBy?.charAt(0) || '无' }}
- </el-avatar>
- <span>{{ detailData.finishBy || '未分配' }}</span>
- </div>
- </el-descriptions-item>
- <el-descriptions-item label="工单状态">
- <el-tag :type="getStatusTagType(detailData.orderStatus)">
- {{ getStatusLabel(detailData.orderStatus) }}
- </el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="工单备注" :span="2">
- {{ detailData.orderRemark || '无' }}
- </el-descriptions-item>
- </el-descriptions>
- <div v-if="detailData.annex" class="attachment-section">
- <h4>附件信息</h4>
- <el-button type="primary" :icon="Download" @click="downloadFile(detailData.annex)">
- 下载附件
- </el-button>
- </div>
- </div>
- </el-drawer>
- <!-- 添加或修改维修工单对话框 -->
- <el-dialog
- :title="title"
- v-model="open"
- width="700px"
- append-to-body
- :close-on-click-modal="false"
- >
- <el-form ref="repairOrderRef" :model="form" :rules="rules" label-width="100px">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="工单编号" prop="orderNo">
- <el-input v-model="form.orderNo" placeholder="请输入工单编号" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="项目名称" prop="projectName">
- <el-input v-model="form.projectName" placeholder="请输入项目名称" disabled />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="工单内容" prop="orderContent">
- <el-input
- v-model="form.orderContent"
- type="textarea"
- :rows="3"
- placeholder="请输入内容"
- disabled
- />
- </el-form-item>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="派单时间" prop="assignTime">
- <el-date-picker
- v-model="form.assignTime"
- type="datetime"
- value-format="YYYY-MM-DD HH:mm:ss"
- placeholder="请选择派单时间"
- disabled
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="完成时间" prop="finishTime" :rules="rules.finishTime">
- <el-date-picker
- v-model="form.finishTime"
- type="datetime"
- value-format="YYYY-MM-DD HH:mm:ss"
- placeholder="请选择完成时间"
- style="width: 100%"
- :disabled-date="disabledDate"
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="责任人" prop="finishBy">
- <el-select
- v-model="form.userId"
- placeholder="请选择责任人"
- clearable
- filterable
- disabled
- style="width: 100%"
- >
- <el-option
- v-for="user in userOptions"
- :key="user.userId"
- :label="user.nickName || user.userName"
- :value="user.userId"
- >
- <div style="display: flex; align-items: center;">
- <el-avatar size="small" style="margin-right: 8px">
- {{ (user.nickName || user.userName).charAt(0) }}
- </el-avatar>
- <span>{{ user.nickName || user.userName }}</span>
- </div>
- </el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="附件上传" prop="annex">
- <file-upload
- v-model="form.annex"
- :on-remove="handleRemoveFile"
- :limit="5"
- :file-size="10"
- />
- </el-form-item>
- <el-form-item label="工单备注" prop="orderRemark">
- <el-input
- v-model="form.orderRemark"
- type="textarea"
- :rows="3"
- placeholder="请输入工单处理备注"
- maxlength="500"
- show-word-limit
- />
- </el-form-item>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="cancel">取 消</el-button>
- <el-button type="primary" @click="submitForm" :loading="submitLoading">
- 确 定
- </el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup name="RepairOrder">
- import { ref, reactive, toRefs, onMounted, computed } from 'vue';
- import {
- listRepairOrder,
- getRepairOrder,
- delRepairOrder,
- addRepairOrder,
- updateRepairOrder,
- deleteFile, getRepairOrderStatistics
- } from "@/api/repairOrder/repairOrder";
- import { listUser } from "@/api/system/user";
- import { ElMessage, ElMessageBox } from 'element-plus';
- // 导入图标
- import {
- Tools,
- Plus,
- Download,
- DocumentCopy,
- Clock,
- Loading,
- CircleCheck,
- Search,
- Refresh,
- View,
- Hide,
- Edit,
- Delete,
- Paperclip
- } from '@element-plus/icons-vue';
- const { proxy } = getCurrentInstance();
- const { repair_status } = proxy.useDict('repair_status');
- // 响应式变量
- const repairOrderList = ref([]);
- const open = ref(false);
- const loading = ref(true);
- const submitLoading = ref(false);
- const showSearch = ref(true);
- const ids = ref([]);
- const single = ref(true);
- const multiple = ref(true);
- const total = ref(0);
- const title = ref("");
- const userOptions = ref([]);
- const detailVisible = ref(false);
- const detailData = ref({});
- const statisticsData = ref({
- total: 0,
- pending: 0,
- processing: 0,
- completed: 0
- });
- // 统计数据
- const statistics = computed(() => statisticsData.value);
- const data = reactive({
- form: {},
- queryParams: {
- isMe: true,
- pageNum: 1,
- pageSize: 10,
- orderNo: null,
- orderContent: null,
- projectName: null,
- orderStatus: null,
- dateRange: [],
- state: Date.now(),
- },
- rules: {
- finishTime: [
- { required: true, message: "完成时间不能为空", trigger: "blur" }
- ],
- orderRemark: [
- { required: true, message: "请填写处理备注", trigger: "blur" }
- ]
- }
- });
- const { queryParams, form, rules } = toRefs(data);
- // 获取状态标签类型
- function getStatusTagType(status) {
- const statusMap = {
- '0': 'warning',
- '1': 'primary',
- '2': 'success'
- };
- return statusMap[status] || 'info';
- }
- // 获取状态标签文本
- function getStatusLabel(status) {
- const dict = repair_status.value.find(item => item.value === status);
- return dict ? dict.label : '未知';
- }
- // 获取用户头像
- function getUserAvatar(userName) {
- // 这里可以根据实际情况返回用户头像URL
- return '';
- }
- // 表格行样式
- function tableRowClassName({ row }) {
- if (row.orderStatus === '0') {
- return 'warning-row';
- } else if (row.orderStatus === '2') {
- return 'success-row';
- }
- return '';
- }
- // 禁用日期(不能选择派单时间之前的日期)
- function disabledDate(time) {
- if (form.value.assignTime) {
- return time.getTime() < new Date(form.value.assignTime).getTime();
- }
- return false;
- }
- // 显示详情
- function showDetail(row) {
- detailData.value = { ...row };
- detailVisible.value = true;
- }
- // 下载文件
- function downloadFile(url) {
- if (!url) {
- ElMessage.warning('暂无附件');
- return;
- }
- window.open(import.meta.env.VITE_APP_BASE_API + url);
- }
- /** 查询维修工单列表 */
- async function getList() {
- loading.value = true;
- try {
- const params = { ...queryParams.value };
- // 处理日期范围
- /*if (dateRange.value && dateRange.value.length === 2) {
- params.startDate = dateRange.value[0];
- params.endDate = dateRange.value[1];
- }*/
- const response = await listRepairOrder(params);
- repairOrderList.value = response.rows;
- total.value = response.total;
- // 获取统计数据
- await getStatistics();
- } catch (error) {
- console.error('获取数据失败:', error);
- ElMessage.error('获取工单列表失败');
- } finally {
- loading.value = false;
- }
- }
- async function getStatistics() {
- try {
- // 如果后端没有统计接口,可以通过查询所有数据来统计
- const response = await getRepairOrderStatistics({isMe: true});
- // 直接更新 statisticsData
- statisticsData.value = {
- total: response.data.total || 0,
- pending: response.data.pending || 0,
- processing: response.data.processing || 0,
- completed: response.data.completed || 0
- };
- // 计算趋势(这里模拟数据,实际应该对比上期数据)
- statisticsData.value.forEach(stat => {
- stat.trend = Math.floor(Math.random() * 30) - 15; // 随机生成-15到15的趋势
- });
- } catch (error) {
- console.error('获取统计数据失败:', error);
- }
- }
- // 删除附件
- function handleRemoveFile(file) {
- ElMessageBox.confirm('确认删除该附件吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- deleteFile(file.url).then(() => {
- form.value.annex = null;
- ElMessage.success("删除成功");
- }).catch(() => {
- ElMessage.error("删除失败");
- });
- }).catch(() => {});
- }
- // 取消按钮
- function cancel() {
- open.value = false;
- reset();
- }
- // 表单重置
- function reset() {
- form.value = {
- id: null,
- orderNo: null,
- orderContent: null,
- projectName: null,
- assignTime: null,
- finishTime: null,
- finishBy: null,
- annex: null,
- userId: null,
- orderStatus: null,
- orderRemark: null,
- createBy: null,
- createTime: null,
- updateBy: null,
- updateTime: null
- };
- proxy.resetForm("repairOrderRef");
- }
- /** 搜索按钮操作 */
- function handleQuery() {
- queryParams.value.pageNum = 1;
- getList();
- }
- /** 重置按钮操作 */
- function resetQuery() {
- proxy.resetForm("queryRef");
- queryParams.value.dateRange = [];
- handleQuery();
- }
- // 多选框选中数据
- function handleSelectionChange(selection) {
- ids.value = selection.map(item => item.id);
- single.value = selection.length !== 1;
- multiple.value = !selection.length;
- }
- /** 新增按钮操作 */
- function handleAdd() {
- reset();
- open.value = true;
- title.value = "新建维修工单";
- }
- // 获取用户列表
- function getUserList() {
- listUser().then(response => {
- userOptions.value = response.rows || [];
- });
- }
- /** 修改按钮操作 */
- function handleUpdate(row) {
- reset();
- const _id = row.id || ids.value;
- getRepairOrder(_id).then(response => {
- form.value = response.data;
- open.value = true;
- title.value = "处理维修工单";
- });
- }
- /** 提交按钮 */
- function submitForm() {
- proxy.$refs["repairOrderRef"].validate(valid => {
- if (valid) {
- submitLoading.value = true;
- // 设置完成人信息
- if (form.value.userId) {
- const user = userOptions.value.find(u => u.userId === form.value.userId);
- if (user) {
- form.value.finishBy = user.nickName || user.userName;
- }
- }
- // 设置工单状态为已完成
- form.value.orderStatus = '2';
- if (form.value.id != null) {
- updateRepairOrder(form.value).then(response => {
- ElMessage.success("处理成功");
- open.value = false;
- getList();
- }).finally(() => {
- submitLoading.value = false;
- });
- } else {
- addRepairOrder(form.value).then(response => {
- ElMessage.success("新增成功");
- open.value = false;
- getList();
- }).finally(() => {
- submitLoading.value = false;
- });
- }
- }
- });
- }
- /** 删除按钮操作 */
- function handleDelete(row) {
- const _ids = row.id || ids.value;
- const deletePromises = [];
- ElMessageBox.confirm('是否确认删除选中的工单?删除后不可恢复!', '警告', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- // 如果是批量删除,检查每个选中项是否有附件
- if (Array.isArray(ids.value) && ids.value.length > 0) {
- repairOrderList.value.forEach(item => {
- if (ids.value.includes(item.id) && item.annex) {
- deletePromises.push(deleteFile(item.annex));
- }
- });
- }
- // 如果是单个删除,检查是否有附件
- else if (row.annex) {
- deletePromises.push(deleteFile(row.annex));
- }
- // 先删除所有附件
- return Promise.all(deletePromises).then(() => {
- // 附件删除成功后删除数据
- return delRepairOrder(_ids);
- });
- }).then(() => {
- getList();
- ElMessage.success("删除成功");
- }).catch((error) => {
- if (error !== 'cancel') {
- ElMessage.error("删除失败");
- }
- });
- }
- /** 导出按钮操作 */
- function handleExport() {
- ElMessageBox.confirm('确定要导出所有维修工单数据吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'info'
- }).then(() => {
- proxy.download('repairOrder/repairOrder/export', {
- ...queryParams.value
- }, `维修工单_${new Date().getTime()}.xlsx`);
- });
- }
- // 初始化
- onMounted(() => {
- getList();
- getUserList();
- });
- </script>
- <style scoped lang="scss">
- .repair-order-container {
- padding: 20px;
- background-color: #f5f7fa;
- min-height: calc(100vh - 84px);
- .page-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20px;
- .page-title {
- font-size: 24px;
- font-weight: 600;
- color: #303133;
- margin: 0;
- display: flex;
- align-items: center;
- .el-icon {
- margin-right: 8px;
- color: #409eff;
- }
- }
- .header-actions {
- display: flex;
- gap: 10px;
- }
- }
- // 统计卡片
- .statistics-cards {
- margin-bottom: 20px;
- .stat-card {
- background: #fff;
- border-radius: 8px;
- padding: 20px;
- display: flex;
- align-items: center;
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
- transition: all 0.3s;
- margin-bottom: 10px;
- &:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.08);
- }
- .stat-icon {
- width: 60px;
- height: 60px;
- border-radius: 12px;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-right: 16px;
- .el-icon {
- font-size: 28px;
- }
- &.blue {
- background: #e6f2ff;
- color: #409eff;
- }
- &.orange {
- background: #fdf6ec;
- color: #e6a23c;
- }
- &.purple {
- background: #f3e8ff;
- color: #9c27b0;
- }
- &.green {
- background: #e8f5e9;
- color: #67c23a;
- }
- }
- .stat-content {
- flex: 1;
- .stat-value {
- font-size: 28px;
- font-weight: 600;
- color: #303133;
- line-height: 1;
- margin-bottom: 8px;
- }
- .stat-label {
- font-size: 14px;
- color: #909399;
- }
- }
- }
- }
- // 搜索卡片
- .search-card {
- margin-bottom: 20px;
- :deep(.el-card__body) {
- padding: 20px 20px 0;
- }
- .el-form-item {
- margin-bottom: 20px;
- }
- }
- // 表格卡片
- .table-card {
- :deep(.el-card__body) {
- padding: 0;
- }
- .table-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20px;
- border-bottom: 1px solid #ebeef5;
- .table-title {
- font-size: 16px;
- font-weight: 600;
- color: #303133;
- }
- .table-tools {
- display: flex;
- gap: 8px;
- }
- }
- .el-table {
- :deep(.el-table__header) {
- th {
- background-color: #f5f7fa;
- color: #303133;
- font-weight: 600;
- }
- }
- :deep(.warning-row) {
- background-color: #fef0f0;
- }
- :deep(.success-row) {
- background-color: #f0f9ff;
- }
- .time-info {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 4px;
- color: #606266;
- .el-icon {
- color: #909399;
- }
- }
- .user-info {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- .el-avatar {
- background-color: #409eff;
- color: #fff;
- font-size: 12px;
- }
- }
- .text-muted {
- color: #c0c4cc;
- }
- }
- }
- // 详情抽屉
- .detail-drawer {
- :deep(.el-drawer__header) {
- margin-bottom: 0;
- padding-bottom: 20px;
- border-bottom: 1px solid #ebeef5;
- }
- .drawer-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- h3 {
- margin: 0;
- font-size: 18px;
- color: #303133;
- }
- }
- .detail-content {
- padding: 20px;
- .detail-value {
- font-weight: 600;
- color: #409eff;
- }
- .attachment-section {
- margin-top: 30px;
- padding-top: 20px;
- border-top: 1px solid #ebeef5;
- h4 {
- margin: 0 0 15px 0;
- font-size: 16px;
- color: #303133;
- }
- }
- }
- }
- // 对话框样式
- :deep(.el-dialog) {
- .el-dialog__header {
- background-color: #f5f7fa;
- padding: 20px;
- .el-dialog__title {
- font-size: 18px;
- color: #303133;
- }
- }
- .el-dialog__body {
- padding: 20px;
- }
- .el-form {
- .el-form-item__label {
- font-weight: 500;
- }
- }
- }
- }
- // 响应式设计
- @media (max-width: 768px) {
- .repair-order-container {
- padding: 10px;
- .page-header {
- flex-direction: column;
- align-items: flex-start;
- gap: 10px;
- .header-actions {
- width: 100%;
- display: flex;
- justify-content: flex-end;
- }
- }
- .statistics-cards {
- .el-col {
- margin-bottom: 10px;
- }
- }
- .search-card {
- :deep(.el-form) {
- .el-form-item {
- display: block;
- margin-bottom: 16px;
- }
- }
- }
- .detail-drawer {
- :deep(.el-drawer) {
- width: 90% !important;
- }
- }
- }
- }
- // 动画效果
- @keyframes fadeIn {
- from {
- opacity: 0;
- transform: translateY(20px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
- }
- .stat-card {
- animation: fadeIn 0.5s ease-out;
- &:nth-child(1) { animation-delay: 0.1s; }
- &:nth-child(2) { animation-delay: 0.2s; }
- &:nth-child(3) { animation-delay: 0.3s; }
- &:nth-child(4) { animation-delay: 0.4s; }
- }
- // 标签样式优化
- :deep(.el-tag) {
- .el-icon {
- margin-right: 4px;
- }
- }
- // 链接样式
- .el-link {
- font-weight: 500;
- }
- // 分页器样式
- :deep(.pagination-container) {
- padding: 20px;
- background: #fff;
- }
- </style>
|