You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
599 lines
19 KiB
599 lines
19 KiB
|
5 days ago
|
<!--
|
||
|
|
* 周调度:勾选案件生成标红模板,手填调度内容,推送人员全员确认后锁定可打印
|
||
|
|
-->
|
||
|
|
<template>
|
||
|
|
<div class="weekly-schedule-container">
|
||
|
|
<a-form class="smart-query-form">
|
||
|
|
<a-row class="smart-query-form-row" v-privilege="'weekly-schedule:query'">
|
||
|
|
<a-form-item label="调度编号" class="smart-query-form-item">
|
||
|
|
<a-input style="width: 180px" v-model:value="queryForm.scheduleNo" placeholder="请输入调度编号" allowClear />
|
||
|
|
</a-form-item>
|
||
|
|
<a-form-item label="状态" class="smart-query-form-item">
|
||
|
|
<a-select style="width: 140px" v-model:value="queryForm.status" placeholder="请选择" allowClear>
|
||
|
|
<a-select-option v-for="item in statusOptions" :key="item.value" :value="item.value">{{ item.desc }}</a-select-option>
|
||
|
|
</a-select>
|
||
|
|
</a-form-item>
|
||
|
|
<a-form-item class="smart-query-form-item">
|
||
|
|
<a-button-group>
|
||
|
|
<a-button type="primary" @click="onSearch" v-privilege="'weekly-schedule:query'">
|
||
|
|
<template #icon><SearchOutlined /></template>
|
||
|
|
查询
|
||
|
|
</a-button>
|
||
|
|
<a-button @click="resetQuery" v-privilege="'weekly-schedule:query'">
|
||
|
|
<template #icon><ReloadOutlined /></template>
|
||
|
|
重置
|
||
|
|
</a-button>
|
||
|
|
</a-button-group>
|
||
|
|
</a-form-item>
|
||
|
|
</a-row>
|
||
|
|
</a-form>
|
||
|
|
|
||
|
|
<div class="section-card">
|
||
|
|
<a-row class="smart-table-btn-block">
|
||
|
|
<div class="smart-table-operate-block">
|
||
|
|
<a-button type="primary" v-privilege="'weekly-schedule:add'" @click="openCreate">
|
||
|
|
<template #icon><PlusOutlined /></template>
|
||
|
|
新增
|
||
|
|
</a-button>
|
||
|
|
<a-radio-group v-model:value="listTab" button-style="solid" class="list-tab" @change="onTabChange">
|
||
|
|
<a-radio-button :value="false">全部</a-radio-button>
|
||
|
|
<a-radio-button :value="true">待我确认</a-radio-button>
|
||
|
|
</a-radio-group>
|
||
|
|
</div>
|
||
|
|
<div class="smart-table-setting-block">
|
||
|
|
<TableOperator v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.CASE.WEEKLY_SCHEDULE" :refresh="queryData" />
|
||
|
|
</div>
|
||
|
|
</a-row>
|
||
|
|
<a-table
|
||
|
|
size="small"
|
||
|
|
:dataSource="tableData"
|
||
|
|
:columns="columns"
|
||
|
|
rowKey="scheduleId"
|
||
|
|
:scroll="{ x: 1200 }"
|
||
|
|
bordered
|
||
|
|
:pagination="false"
|
||
|
|
:loading="tableLoading"
|
||
|
|
>
|
||
|
|
<template #bodyCell="{ record, column }">
|
||
|
|
<template v-if="column.dataIndex === 'status'">
|
||
|
|
<a-tag :color="getWeeklyScheduleStatusColor(record.status)">{{ record.statusName || getWeeklyScheduleStatusName(record.status) }}</a-tag>
|
||
|
|
</template>
|
||
|
|
<template v-else-if="column.dataIndex === 'progress'">
|
||
|
|
{{ record.confirmedCount || 0 }}/{{ record.memberCount || 0 }}
|
||
|
|
</template>
|
||
|
|
<template v-else-if="column.dataIndex === 'createTime'">
|
||
|
|
{{ formatTime(record.createTime) }}
|
||
|
|
</template>
|
||
|
|
<template v-else-if="column.dataIndex === 'action'">
|
||
|
|
<div class="smart-table-operate">
|
||
|
|
<a-button type="link" size="small" v-privilege="'weekly-schedule:view'" @click="openDetail(record)">查看</a-button>
|
||
|
|
<a-button type="link" size="small" v-if="record.canPush" v-privilege="'weekly-schedule:push'" @click="handlePush(record)">推送</a-button>
|
||
|
|
<a-popconfirm title="确认调度内容后不可更改,确定确认?" ok-text="确定" cancel-text="取消" @confirm="handleConfirm(record)">
|
||
|
|
<a-button type="link" size="small" v-if="record.canConfirm" v-privilege="'weekly-schedule:confirm'">确认</a-button>
|
||
|
|
</a-popconfirm>
|
||
|
|
<a-button type="link" size="small" v-if="record.canPrint" v-privilege="'weekly-schedule:print'" @click="handlePrint(record)">打印</a-button>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
</template>
|
||
|
|
</a-table>
|
||
|
|
<div class="smart-query-table-page">
|
||
|
|
<a-pagination
|
||
|
|
showSizeChanger
|
||
|
|
showQuickJumper
|
||
|
|
show-less-items
|
||
|
|
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||
|
|
v-model:current="queryForm.pageNum"
|
||
|
|
v-model:pageSize="queryForm.pageSize"
|
||
|
|
:total="pagination.total"
|
||
|
|
@change="onPageChange"
|
||
|
|
@showSizeChange="onPageChange"
|
||
|
|
:show-total="(total) => `共${total}条`"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<a-modal
|
||
|
|
v-model:open="createVisible"
|
||
|
|
title="新增周调度"
|
||
|
|
:width="1180"
|
||
|
|
:maskClosable="false"
|
||
|
|
:confirm-loading="createLoading"
|
||
|
|
@cancel="closeCreate"
|
||
|
|
>
|
||
|
|
<div class="create-layout">
|
||
|
|
<div class="create-left">
|
||
|
|
<a-form layout="inline" class="case-search-form">
|
||
|
|
<a-form-item label="案件名称">
|
||
|
|
<a-input v-model:value="caseQuery.caseName" placeholder="关键字模糊搜索" allowClear style="width: 160px" />
|
||
|
|
</a-form-item>
|
||
|
|
<a-form-item label="案件编号">
|
||
|
|
<a-input v-model:value="caseQuery.caseNo" placeholder="案件编号" allowClear style="width: 140px" />
|
||
|
|
</a-form-item>
|
||
|
|
<a-form-item>
|
||
|
|
<a-button type="primary" @click="searchCases">搜索</a-button>
|
||
|
|
</a-form-item>
|
||
|
|
</a-form>
|
||
|
|
<a-table
|
||
|
|
size="small"
|
||
|
|
:dataSource="caseTableData"
|
||
|
|
:columns="caseColumns"
|
||
|
|
rowKey="caseId"
|
||
|
|
:pagination="false"
|
||
|
|
:loading="caseLoading"
|
||
|
|
:row-selection="{ selectedRowKeys: selectedCaseIds, onChange: onSelectCases }"
|
||
|
|
:scroll="{ y: 280 }"
|
||
|
|
bordered
|
||
|
|
/>
|
||
|
|
<div class="smart-query-table-page">
|
||
|
|
<a-pagination
|
||
|
|
size="small"
|
||
|
|
:pageSize="caseQuery.pageSize"
|
||
|
|
v-model:current="caseQuery.pageNum"
|
||
|
|
:total="casePagination.total"
|
||
|
|
@change="onCasePageChange"
|
||
|
|
:show-total="(total) => `共${total}条`"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="create-right">
|
||
|
|
<div class="paper-preview">
|
||
|
|
<WeeklyScheduleMinutes
|
||
|
|
:form="createForm"
|
||
|
|
:cases="selectedCases"
|
||
|
|
:members="selectedMembers"
|
||
|
|
editable
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<div class="member-block">
|
||
|
|
<div class="member-header">
|
||
|
|
<span>参加调度人员</span>
|
||
|
|
<a-button size="small" @click="openEmployeeSelect">选择人员</a-button>
|
||
|
|
</div>
|
||
|
|
<div class="member-tags">
|
||
|
|
<a-tag v-for="item in selectedMembers" :key="item.employeeId" closable @close="removeMember(item.employeeId)">
|
||
|
|
{{ item.actualName }}
|
||
|
|
</a-tag>
|
||
|
|
<span v-if="!selectedMembers.length" class="empty-hint">请勾选参加调度人员进行推送</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<template #footer>
|
||
|
|
<a-button @click="closeCreate">取消</a-button>
|
||
|
|
<a-button @click="submitCreate(false)" :loading="createLoading" v-privilege="'weekly-schedule:add'">保存草稿</a-button>
|
||
|
|
<a-button type="primary" @click="submitCreate(true)" :loading="createLoading" v-privilege="'weekly-schedule:push'">推送</a-button>
|
||
|
|
</template>
|
||
|
|
</a-modal>
|
||
|
|
|
||
|
|
<EmployeeTableSelectModal ref="selectEmployeeModal" @selectData="onSelectEmployees" />
|
||
|
|
|
||
|
|
<a-drawer v-model:open="detailVisible" title="周调度详情" placement="right" :width="780">
|
||
|
|
<div class="paper-preview" v-if="currentRecord">
|
||
|
|
<div class="meta-line">调度编号:{{ currentRecord.scheduleNo }} 状态:{{ currentRecord.statusName }} 创建人:{{ currentRecord.createUserName || '-' }}</div>
|
||
|
|
<WeeklyScheduleMinutes
|
||
|
|
:form="currentRecord"
|
||
|
|
:cases="currentRecord.caseList || []"
|
||
|
|
:members="currentRecord.memberList || []"
|
||
|
|
/>
|
||
|
|
<div class="content-label">确认进度</div>
|
||
|
|
<a-tag v-for="item in currentRecord.memberList || []" :key="item.employeeId" :color="item.confirmedFlag ? 'success' : 'warning'">
|
||
|
|
{{ item.employeeName }}{{ item.confirmedFlag ? '(已确认)' : '(待确认)' }}
|
||
|
|
</a-tag>
|
||
|
|
<div class="detail-actions">
|
||
|
|
<a-popconfirm v-if="currentRecord.canConfirm" title="确认调度内容后不可更改,确定确认?" @confirm="handleConfirm(currentRecord)">
|
||
|
|
<a-button type="primary" v-privilege="'weekly-schedule:confirm'">确认</a-button>
|
||
|
|
</a-popconfirm>
|
||
|
|
<a-button v-if="currentRecord.canPush" v-privilege="'weekly-schedule:push'" @click="handlePush(currentRecord)">推送</a-button>
|
||
|
|
<a-button v-if="currentRecord.canPrint" v-privilege="'weekly-schedule:print'" @click="printWeeklySchedule(currentRecord)">打印</a-button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</a-drawer>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup>
|
||
|
|
import { reactive, ref, onMounted } from 'vue';
|
||
|
|
import { message } from 'ant-design-vue';
|
||
|
|
import { SearchOutlined, ReloadOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||
|
|
import _ from 'lodash';
|
||
|
|
import dayjs from 'dayjs';
|
||
|
|
import TableOperator from '/@/components/support/table-operator/index.vue';
|
||
|
|
import EmployeeTableSelectModal from '/@/components/system/employee-table-select-modal/index.vue';
|
||
|
|
import { PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||
|
|
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
|
||
|
|
import { smartSentry } from '/@/lib/smart-sentry';
|
||
|
|
import { weeklyScheduleApi } from '/@/api/business/case-management/weekly-schedule-api.js';
|
||
|
|
import { employeeApi } from '/@/api/system/employee-api';
|
||
|
|
import {
|
||
|
|
WEEKLY_SCHEDULE_STATUS_ENUM,
|
||
|
|
getWeeklyScheduleStatusName,
|
||
|
|
getWeeklyScheduleStatusColor,
|
||
|
|
} from '/@/constants/business/case-management/case-supervision-const.js';
|
||
|
|
import { printWeeklySchedule } from '/@/utils/print-weekly-schedule.js';
|
||
|
|
import WeeklyScheduleMinutes from './weekly-schedule-minutes.vue';
|
||
|
|
import { useUserStore } from '/@/store/modules/system/user';
|
||
|
|
|
||
|
|
const statusOptions = Object.values(WEEKLY_SCHEDULE_STATUS_ENUM);
|
||
|
|
const listTab = ref(false);
|
||
|
|
|
||
|
|
const columns = ref([
|
||
|
|
{ title: '调度编号', dataIndex: 'scheduleNo', width: 160 },
|
||
|
|
{ title: '调度内容', dataIndex: 'scheduleContent', width: 260, ellipsis: true },
|
||
|
|
{ title: '案件数', dataIndex: 'caseCount', width: 80, align: 'center' },
|
||
|
|
{ title: '确认进度', dataIndex: 'progress', width: 100, align: 'center' },
|
||
|
|
{ title: '状态', dataIndex: 'status', width: 100, align: 'center' },
|
||
|
|
{ title: '创建人', dataIndex: 'createUserName', width: 100 },
|
||
|
|
{ title: '创建时间', dataIndex: 'createTime', width: 160 },
|
||
|
|
{ title: '操作', dataIndex: 'action', fixed: 'right', width: 200 },
|
||
|
|
]);
|
||
|
|
|
||
|
|
const queryFormState = {
|
||
|
|
scheduleNo: '',
|
||
|
|
status: undefined,
|
||
|
|
pendingMine: false,
|
||
|
|
pageNum: 1,
|
||
|
|
pageSize: 10,
|
||
|
|
};
|
||
|
|
const queryForm = reactive(_.cloneDeep(queryFormState));
|
||
|
|
const tableLoading = ref(false);
|
||
|
|
const tableData = ref([]);
|
||
|
|
const pagination = reactive({ total: 0 });
|
||
|
|
|
||
|
|
const createVisible = ref(false);
|
||
|
|
const createLoading = ref(false);
|
||
|
|
const userStore = useUserStore();
|
||
|
|
const createForm = reactive({
|
||
|
|
meetingTime: undefined,
|
||
|
|
meetingPlace: '',
|
||
|
|
scheduleUnit: '',
|
||
|
|
hostName: '',
|
||
|
|
recorderName: '',
|
||
|
|
});
|
||
|
|
const selectedCases = ref([]);
|
||
|
|
const selectedMembers = ref([]);
|
||
|
|
const employeeMap = ref([]);
|
||
|
|
const selectEmployeeModal = ref();
|
||
|
|
|
||
|
|
const caseQuery = reactive({ caseNo: '', caseName: '', pageNum: 1, pageSize: 8 });
|
||
|
|
const caseTableData = ref([]);
|
||
|
|
const casePagination = reactive({ total: 0 });
|
||
|
|
const caseLoading = ref(false);
|
||
|
|
const caseColumns = [
|
||
|
|
{ title: '案件名称', dataIndex: 'caseName', ellipsis: true },
|
||
|
|
{ title: '案件编号', dataIndex: 'caseNo', width: 140 },
|
||
|
|
{ title: '主办民警', dataIndex: 'handlerName', width: 90 },
|
||
|
|
{ title: '办案单位', dataIndex: 'handleDept', width: 130, ellipsis: true },
|
||
|
|
];
|
||
|
|
|
||
|
|
const selectedCaseIds = ref([]);
|
||
|
|
const detailVisible = ref(false);
|
||
|
|
const currentRecord = ref(null);
|
||
|
|
|
||
|
|
function resetQuery() {
|
||
|
|
const pageSize = queryForm.pageSize;
|
||
|
|
Object.assign(queryForm, _.cloneDeep(queryFormState));
|
||
|
|
queryForm.pageSize = pageSize;
|
||
|
|
listTab.value = false;
|
||
|
|
queryData();
|
||
|
|
}
|
||
|
|
|
||
|
|
function onSearch() {
|
||
|
|
queryForm.pageNum = 1;
|
||
|
|
queryData();
|
||
|
|
}
|
||
|
|
|
||
|
|
function onTabChange() {
|
||
|
|
queryForm.pendingMine = listTab.value;
|
||
|
|
queryForm.pageNum = 1;
|
||
|
|
queryData();
|
||
|
|
}
|
||
|
|
|
||
|
|
async function queryData() {
|
||
|
|
queryForm.pendingMine = listTab.value;
|
||
|
|
tableLoading.value = true;
|
||
|
|
try {
|
||
|
|
const res = await weeklyScheduleApi.query(queryForm);
|
||
|
|
tableData.value = res.data?.list || [];
|
||
|
|
pagination.total = res.data?.total || 0;
|
||
|
|
} catch (e) {
|
||
|
|
smartSentry.captureError(e);
|
||
|
|
} finally {
|
||
|
|
tableLoading.value = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function onPageChange(page, pageSize) {
|
||
|
|
queryForm.pageNum = page;
|
||
|
|
queryForm.pageSize = pageSize;
|
||
|
|
queryData();
|
||
|
|
}
|
||
|
|
|
||
|
|
function emptyCreateForm() {
|
||
|
|
createForm.meetingTime = undefined;
|
||
|
|
createForm.meetingPlace = '';
|
||
|
|
createForm.scheduleUnit = userStore.departmentName || '';
|
||
|
|
createForm.hostName = '';
|
||
|
|
createForm.recorderName = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
async function openCreate() {
|
||
|
|
emptyCreateForm();
|
||
|
|
selectedCases.value = [];
|
||
|
|
selectedCaseIds.value = [];
|
||
|
|
selectedMembers.value = [];
|
||
|
|
createVisible.value = true;
|
||
|
|
await loadEmployees();
|
||
|
|
await searchCases();
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeCreate() {
|
||
|
|
createVisible.value = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function searchCases() {
|
||
|
|
caseQuery.pageNum = 1;
|
||
|
|
await loadCasePage();
|
||
|
|
}
|
||
|
|
|
||
|
|
async function loadCasePage() {
|
||
|
|
caseLoading.value = true;
|
||
|
|
try {
|
||
|
|
const res = await weeklyScheduleApi.searchCase(caseQuery);
|
||
|
|
caseTableData.value = res.data?.list || [];
|
||
|
|
casePagination.total = res.data?.total || 0;
|
||
|
|
} catch (e) {
|
||
|
|
smartSentry.captureError(e);
|
||
|
|
} finally {
|
||
|
|
caseLoading.value = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function onCasePageChange(page) {
|
||
|
|
caseQuery.pageNum = page;
|
||
|
|
loadCasePage();
|
||
|
|
}
|
||
|
|
|
||
|
|
function onSelectCases(keys) {
|
||
|
|
const map = new Map(selectedCases.value.map((item) => [item.caseId, item]));
|
||
|
|
caseTableData.value.forEach((row) => {
|
||
|
|
const existing = map.get(row.caseId);
|
||
|
|
map.set(row.caseId, {
|
||
|
|
...row,
|
||
|
|
itemContent: existing?.itemContent || '',
|
||
|
|
});
|
||
|
|
});
|
||
|
|
selectedCases.value = keys.map((id) => map.get(id)).filter(Boolean);
|
||
|
|
selectedCaseIds.value = keys;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function loadEmployees() {
|
||
|
|
try {
|
||
|
|
const res = await employeeApi.queryAll();
|
||
|
|
employeeMap.value = res.data || [];
|
||
|
|
} catch (e) {
|
||
|
|
smartSentry.captureError(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function openEmployeeSelect() {
|
||
|
|
selectEmployeeModal.value?.showModal(selectedMembers.value.map((item) => item.employeeId));
|
||
|
|
}
|
||
|
|
|
||
|
|
function onSelectEmployees(ids) {
|
||
|
|
const list = selectedMembers.value.slice();
|
||
|
|
(ids || []).forEach((id) => {
|
||
|
|
if (list.some((item) => item.employeeId === id)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const emp = employeeMap.value.find((item) => item.employeeId === id);
|
||
|
|
list.push({ employeeId: id, actualName: emp?.actualName || String(id) });
|
||
|
|
});
|
||
|
|
selectedMembers.value = list;
|
||
|
|
}
|
||
|
|
|
||
|
|
function removeMember(employeeId) {
|
||
|
|
selectedMembers.value = selectedMembers.value.filter((item) => item.employeeId !== employeeId);
|
||
|
|
}
|
||
|
|
|
||
|
|
async function submitCreate(pushFlag) {
|
||
|
|
if (!selectedCases.value.length) {
|
||
|
|
message.warning('请勾选调度案件');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const itemContentList = selectedCases.value.map((item) => item.itemContent || '');
|
||
|
|
if (pushFlag && !itemContentList.some((text) => String(text).trim())) {
|
||
|
|
message.warning('请输入调度内容');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (pushFlag && !selectedMembers.value.length) {
|
||
|
|
message.warning('请勾选参加调度人员');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
createLoading.value = true;
|
||
|
|
try {
|
||
|
|
await weeklyScheduleApi.create({
|
||
|
|
caseIdList: selectedCases.value.map((item) => item.caseId),
|
||
|
|
itemContentList,
|
||
|
|
meetingTime: createForm.meetingTime,
|
||
|
|
meetingPlace: createForm.meetingPlace,
|
||
|
|
scheduleUnit: createForm.scheduleUnit,
|
||
|
|
hostName: createForm.hostName,
|
||
|
|
recorderName: createForm.recorderName,
|
||
|
|
memberIdList: selectedMembers.value.map((item) => item.employeeId),
|
||
|
|
pushFlag,
|
||
|
|
});
|
||
|
|
message.success(pushFlag ? '已推送,等待参加人员确认' : '草稿已保存');
|
||
|
|
closeCreate();
|
||
|
|
queryData();
|
||
|
|
} catch (e) {
|
||
|
|
smartSentry.captureError(e);
|
||
|
|
} finally {
|
||
|
|
createLoading.value = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async function openDetail(record) {
|
||
|
|
try {
|
||
|
|
const res = await weeklyScheduleApi.detail(record.scheduleId);
|
||
|
|
currentRecord.value = res.data;
|
||
|
|
detailVisible.value = true;
|
||
|
|
} catch (e) {
|
||
|
|
smartSentry.captureError(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async function handlePush(record) {
|
||
|
|
try {
|
||
|
|
const res = await weeklyScheduleApi.push(record.scheduleId);
|
||
|
|
message.success(res.msg || res.data || '已推送');
|
||
|
|
queryData();
|
||
|
|
if (detailVisible.value) {
|
||
|
|
openDetail(record);
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
smartSentry.captureError(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async function handleConfirm(record) {
|
||
|
|
try {
|
||
|
|
const res = await weeklyScheduleApi.confirm(record.scheduleId);
|
||
|
|
message.success(res.msg || res.data || '确认成功');
|
||
|
|
queryData();
|
||
|
|
if (detailVisible.value) {
|
||
|
|
openDetail(record);
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
smartSentry.captureError(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
async function handlePrint(record) {
|
||
|
|
try {
|
||
|
|
const res = await weeklyScheduleApi.detail(record.scheduleId);
|
||
|
|
printWeeklySchedule(res.data);
|
||
|
|
} catch (e) {
|
||
|
|
smartSentry.captureError(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatTime(value) {
|
||
|
|
if (!value) {
|
||
|
|
return '-';
|
||
|
|
}
|
||
|
|
return dayjs(value).isValid() ? dayjs(value).format('YYYY-MM-DD HH:mm') : value;
|
||
|
|
}
|
||
|
|
|
||
|
|
onMounted(() => {
|
||
|
|
queryData();
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="less" scoped>
|
||
|
|
.weekly-schedule-container {
|
||
|
|
padding: 16px;
|
||
|
|
|
||
|
|
.section-card {
|
||
|
|
background: white;
|
||
|
|
border-radius: 8px;
|
||
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
|
|
padding: 16px;
|
||
|
|
margin-bottom: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.list-tab {
|
||
|
|
margin-left: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
:deep(.smart-table-operate) {
|
||
|
|
display: flex;
|
||
|
|
gap: 4px;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.create-layout {
|
||
|
|
display: flex;
|
||
|
|
gap: 16px;
|
||
|
|
min-height: 460px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.create-left,
|
||
|
|
.create-right {
|
||
|
|
flex: 1;
|
||
|
|
min-width: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.case-search-form {
|
||
|
|
margin-bottom: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.paper-preview {
|
||
|
|
border: 1px solid #e8e8e8;
|
||
|
|
border-radius: 6px;
|
||
|
|
padding: 12px;
|
||
|
|
background: #fafafa;
|
||
|
|
max-height: 560px;
|
||
|
|
overflow: auto;
|
||
|
|
}
|
||
|
|
|
||
|
|
.case-block {
|
||
|
|
border: 1px solid #f0f0f0;
|
||
|
|
background: #fff;
|
||
|
|
padding: 8px 12px;
|
||
|
|
margin-bottom: 8px;
|
||
|
|
line-height: 1.9;
|
||
|
|
}
|
||
|
|
|
||
|
|
.label {
|
||
|
|
display: inline-block;
|
||
|
|
width: 80px;
|
||
|
|
color: #595959;
|
||
|
|
}
|
||
|
|
|
||
|
|
.red-field {
|
||
|
|
color: #cf1322;
|
||
|
|
font-weight: 600;
|
||
|
|
}
|
||
|
|
|
||
|
|
.content-label {
|
||
|
|
margin: 8px 0 6px;
|
||
|
|
font-weight: 600;
|
||
|
|
}
|
||
|
|
|
||
|
|
.content-text {
|
||
|
|
white-space: pre-wrap;
|
||
|
|
min-height: 48px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.empty-hint {
|
||
|
|
color: #8c8c8c;
|
||
|
|
font-size: 13px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.member-block {
|
||
|
|
margin-top: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.member-header {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
margin-bottom: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.member-tags {
|
||
|
|
min-height: 32px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.meta-line {
|
||
|
|
line-height: 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
.detail-actions {
|
||
|
|
margin-top: 16px;
|
||
|
|
display: flex;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
</style>
|