| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920 |
- <template>
- <div class="shift-schedule-container">
- <ContentWrap>
- <el-table v-loading="loading" :data="tableData" border @selection-change="handleSelectionChange"
- @sort-change="handleSortChange" class="shift-schedule-table" ref="tableRef" :row-class-name="getRowClassName">
- <el-table-column type="selection" width="55" fixed="left" :selectable="isSelectable" />
- <el-table-column label="日期" prop="date" width="170" align="center" fixed="left" sortable>
- <template #default="{ row }">
- <div class="date-cell">
- <el-date-picker v-model="row.date" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
- :clearable="false" class="!w-120px" :disabled="!canEdit(row)" @change="handleDateChange(row)" />
- </div>
- </template>
- </el-table-column>
- <el-table-column label="星期" prop="week" width="80" align="center" />
- <!-- 检验员 -->
- <el-table-column label="检验员" prop="checkers" width="300" align="center">
- <template #default="{ row }">
- <div>
- <!-- 不可编辑状态:只显示检验员名称 -->
- <div v-if="!canEdit(row)" class="checker-display">
- {{ getCheckerNames(row) || '-' }}
- </div>
- <!-- 可编辑状态:使用Popover -->
- <el-popover v-else placement="bottom-start" :width="600" trigger="click"
- popper-class="checker-select-popover" @show="() => handlePopoverShow(row)">
- <template #reference>
- <div class="checker-trigger" :class="{ 'has-checkers': getCheckerNames(row) }" @click.stop>
- <span class="checker-text">{{ getCheckerNames(row) || '请选择检验员' }}</span>
- <Icon icon="ep:edit" class="edit-icon ml-5px" />
- </div>
- </template>
- <!-- Popover内容 -->
- <div class="popover-content" @click.stop>
- <CheckerSelect :ref="(el) => setCheckerSelectRef(el, row.id)"
- :dept-id="userStore.getUser.deptId?.toString() || props.relateDepartment" v-model="inspectors"
- :multiple="true" :has-data="true"
- @change="(checkers) => handleCheckerSelectChange(checkers, row)" />
- </div>
- </el-popover>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="检验类型" prop="checkType" width="150" align="center">
- <template #default="{ row }">
- {{ row.checkType === '100' ? '定期检验' : '年度检查' }}
- </template>
- </el-table-column>
- <el-table-column label="使用单位" prop="unitName" width="150" align="center" show-overflow-tooltip sortable />
- <el-table-column label="管道使用地址" prop="pipeAddress" width="200" align="center" show-overflow-tooltip />
- <el-table-column label="联系人" prop="contact" width="100" align="center" />
- <el-table-column label="电话" prop="contactPhone" width="130" align="center" />
- <!-- 管道介质 -->
- <el-table-column label="管道介质" prop="pipeMedium" width="150" align="center">
- <template #default="{ row }">
- <div>
- <el-tag v-for="m in (row.pipeMedium || [])" :key="m" size="small" class="mr-5px mb-5px" type="primary">
- {{ m }}
- </el-tag>
- <span v-if="!row.pipeMedium || row.pipeMedium.length === 0">-</span>
- </div>
- </template>
- </el-table-column>
- <!-- 管线长度 -->
- <el-table-column label="管线长度 (m)" prop="pipeLengthTotal" width="120" align="center">
- <template #default="{ row }">
- <span class="font-mono font-semibold text-blue-800">
- {{ formatPipeLength(row.pipeLengthTotal) }}
- </span>
- </template>
- </el-table-column>
- <el-table-column label="区域街道" prop="equipStreetName" width="120" align="center">
- <template #default="{ row }">
- <span>
- {{ row.equipDistrictName + ' ' + row.equipStreetName || '-' }}
- </span>
- </template>
- </el-table-column>
- <el-table-column label="上次报告编号" prop="lastLegalPeriodicalInspectionReportNo" width="150" align="center" />
- <el-table-column label="监督报告编号" prop="lastMaintenanceReportNo" width="150" align="center" />
- <!-- 状态 -->
- <el-table-column label="状态" prop="status" width="100" align="center" fixed="right">
- <template #header>
- <el-tooltip placement="top">
- <template #content>
- <div class="status-legend">
- <div class="legend-item">
- <span class="status-dot" style="background-color: #409eff;"></span>
- <span>已排期</span>
- </div>
- <div class="legend-item">
- <span class="status-dot" style="background-color: #e6a23c;"></span>
- <span>待约检</span>
- </div>
- <div class="legend-item">
- <span class="status-dot" style="background-color: #67c23a;"></span>
- <span>已受理</span>
- </div>
- <div class="legend-item">
- <span class="status-dot" style="background-color: #f56c6c;"></span>
- <span>检测中</span>
- </div>
- </div>
- </template>
- <div class="flex items-center justify-center gap-6px cursor-help">
- <span>状态</span>
- <Icon icon="ep:question-filled" class="text-gray-400" :size="14" />
- </div>
- </el-tooltip>
- </template>
- <template #default="{ row }">
- <div class="inline-flex items-center gap-6px">
- <span class="inline-block w-10px h-10px rounded-full" :class="getStatusClass(row.status)"></span>
- <span>{{ getStatusText(row.status) }}</span>
- </div>
- </template>
- </el-table-column>
- <!-- 操作 -->
- <el-table-column label="操作" width="120" align="center" fixed="right">
- <template #default="{ row }">
- <el-tag v-if="row.isCopied && !row.submitted" type="warning" size="small">已复制</el-tag>
- <el-button v-else size="small" :type="row.modified ? 'success' : 'primary'"
- :disabled="row.status === 100 || !canEdit(row)" @click="handleCopy(row)">
- 复制
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </ContentWrap>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, onMounted, defineProps, nextTick, computed } from 'vue'
- import { ElMessage } from 'element-plus'
- import { Icon } from '@/components/Icon'
- import { EquipPipeSchedulingApi } from "@/api/pressure2/pipescheduling";
- import dayjs from 'dayjs'
- import 'dayjs/locale/zh-cn'
- import CheckerSelect from '@/views/pressure2/components/CheckerSelect/index.vue'
- import type { CheckerItem } from '@/views/pressure2/components/CheckerSelect/index.vue'
- import { useUserStoreWithOut } from '@/store/modules/user'
- const props = defineProps<{
- relateDepartment: string
- startDate?: string
- endDate?: string
- checkType?: string
- unitName?: string
- status?: string
- }>()
- // ==================== 数据定义 ====================
- interface ScheduleRow {
- id?: string
- index?: number // 行索引
- sourceIndex?: number // 源行索引
- date: string
- week: string
- checkers?: string[] // 检验员ID数组(用于提交)
- teamList?: any[] // 团队列表(后端返回的完整数据)
- checkType?: string
- unitName?: string
- pipeAddress?: string // 管道使用地址
- contact?: string
- contactPhone?: string
- pipeMedium?: string[] // 管道介质
- pipeLengthTotal?: string // 管道长度
- equipDistrictName?: string // 设备所在区域名称
- equipStreetName?: string // 设备所在街道名称
- lastLegalPeriodicalInspectionReportNo?: string // 上次定检报告编号
- confirmOrderId?: string // 确认订单ID
- modified?: boolean // 是否被修改
- originalData?: any // 原始数据,用于比较
- lastYearReportNo?: string // 上次年检报告编号
- lastMaintenanceReportNo?: string // 监督检验报告编号
- status?: number // 状态, 100 已排期 200 待约检 300 已受理 400 检测中
- isCopied?: boolean // 是否为复制的行
- submitted?: boolean // 是否已提交
- }
- const loading = ref(false)
- const exportLoading = ref(false)
- const tableData = ref<ScheduleRow[]>([])
- const selectedRows = ref<ScheduleRow[]>([])
- const tableRef = ref()
- // 处理选择变化
- const handleSelectionChange = (val: ScheduleRow[]) => {
- selectedRows.value = val
- }
- // 只有已排期状态才能勾选
- const isSelectable = (row: ScheduleRow): boolean => {
- return row.status === 100
- }
- // 用户store
- const userStore = useUserStoreWithOut()
- // Popover相关状态
- const currentEditingRow = ref<ScheduleRow | null>(null)
- const checkerSelectRefs = ref<Record<string, any>>({})
- // 查询参数 - 从 props 计算
- const queryParams = computed(() => ({
- startDate: props.startDate || '',
- endDate: props.endDate || '',
- checkType: props.checkType || '',
- unitName: props.unitName || '',
- status: props.status || '',
- orderBy: sortOrderBy.value,
- orderType: sortOrderType.value,
- relateDepartment: props.relateDepartment || ''
- }))
- // 排序参数
- const sortOrderBy = ref('')
- const sortOrderType = ref('')
- // ==================== 方法 ====================
- // 获取检验员昵称列表(用于显示)
- const getCheckerNames = (row: ScheduleRow): string => {
- if (row.teamList && row.teamList.length > 0) {
- // 从 teamList 中获取所有检验员名称,用顿号分隔
- const allMembers: string[] = [];
- row.teamList.forEach(team => {
- // 添加组长
- if (team.leaders && team.leaders.length > 0) {
- team.leaders.forEach(leader => {
- if (leader.nickname) {
- allMembers.push(leader.nickname);
- } else if (leader.id) {
- allMembers.push(leader.id);
- }
- });
- }
- // 添加成员
- if (team.members && team.members.length > 0) {
- team.members.forEach(member => {
- if (member.nickname) {
- allMembers.push(member.nickname);
- } else if (member.id) {
- allMembers.push(member.id);
- }
- });
- }
- });
- return allMembers.join('、') || '';
- } else if (row.checkers && row.checkers.length > 0) {
- // 如果只有 checkers ID 列表,直接显示 ID
- return row.checkers.join('、');
- }
- return ''
- }
- // 设置 CheckerSelect 引用
- const setCheckerSelectRef = (el: any, rowId: string) => {
- if (el) {
- checkerSelectRefs.value[rowId] = el
- }
- }
- const inspectors = ref()
- // 处理 Popover 显示
- const handlePopoverShow = async (row: ScheduleRow) => {
- if (!canEdit(row)) {
- return
- }
- inspectors.value = row.inspectors
- currentEditingRow.value = row
- const checkerSelectRef = checkerSelectRefs.value[row.id]
- // 加载检验员列表
- const deptId = userStore.getUser.deptId?.toString() || props.relateDepartment
- await checkerSelectRef.getCheckerList(deptId)
- console.log(row.inspectors)
- }
- // 关闭Popover
- const closePopover = () => {
- currentEditingRow.value = null
- }
- // 处理检验员选择变化
- const handleCheckerSelectChange = (selectedCheckers: CheckerItem[], row: ScheduleRow) => {
- if (!row) {
- return
- }
- // 同步更新checkers数组(用于提交)- 只需要memberId
- row.checkers = selectedCheckers.map(c => c.memberId.toString())
- // 构建 teamList
- const teamMap = new Map<string, any>()
- selectedCheckers.forEach(item => {
- const groupTeamId = String(item.groupTeamId || '')
- if (!teamMap.has(groupTeamId)) {
- teamMap.set(groupTeamId, {
- groupTeamId: groupTeamId,
- leaders: [],
- members: []
- })
- }
- const team = teamMap.get(groupTeamId)
- if (item.isLeader) {
- team.leaders.push({
- id: item.memberId,
- nickname: item.member?.nickname || ''
- })
- } else {
- team.members.push({
- id: item.memberId,
- nickname: item.member?.nickname || ''
- })
- }
- })
- row.teamList = Array.from(teamMap.values())
- // 标记为已修改并自动保存
- row.modified = true
- autoSaveRow(row)
- }
- // 处理日期变更
- const handleDateChange = (row: ScheduleRow) => {
- if (!row.date) {
- return
- }
- // 更新星期
- row.week = calculateWeek(row.date)
- // 标记为已修改并自动保存
- row.modified = true
- autoSaveRow(row)
- }
- // 通过日期计算星期
- const calculateWeek = (dateStr: string): string => {
- const weekMap = ['日', '一', '二', '三', '四', '五', '六']
- const week = dayjs(dateStr).day()
- return weekMap[week]
- }
- // 获取状态文本
- const getStatusText = (status: number | string | null | undefined): string => {
- if (status === null || status === undefined) {
- return '未知'
- }
- const statusMap: Record<number, string> = {
- 100: '已排期',
- 200: '待约检',
- 300: '已受理',
- 400: '检测中'
- }
- return statusMap[Number(status)] || '未知'
- }
- // 格式化管线长度,去掉小数点后无效的0
- const formatPipeLength = (val: string | undefined): string => {
- if (!val) return '-'
- const num = parseFloat(val)
- if (isNaN(num)) return '-'
- return String(num)
- }
- // 获取状态样式类
- const getStatusClass = (status: number | string | null | undefined): string => {
- if (status === null || status === undefined) {
- return ''
- }
- const classMap: Record<number, string> = {
- 100: 'dot-scheduled',
- 200: 'dot-pending-appointment',
- 300: 'dot-accepted',
- 400: 'dot-testing'
- }
- return classMap[Number(status)] || ''
- }
- // 判断是否可以编辑
- const canEdit = (row: ScheduleRow): boolean => {
- // 受理前(状态为 100 已排期或 200 待约检)的行可以编辑
- if (row.status === 100 || row.status === 200) {
- return true
- }
- // 其他行不可编辑
- return false
- }
- // 获取行类名
- const getRowClassName = ({ row }: { row: ScheduleRow }): string => {
- if (row.isCopied && !row.submitted) {
- return 'copied-row'
- }
- if (row.modified) {
- return 'modified-row'
- }
- return ''
- }
- // 复制行
- const handleCopy = (row: ScheduleRow) => {
- // 限制只有有 confirmOrderId 的情况下才能复制
- if (!row.confirmOrderId) {
- ElMessage.warning('只有已确认的订单才能复制')
- return
- }
- // 计算下一天的日期
- let nextDate = ''
- let nextWeek = ''
- if (row.date) {
- nextDate = dayjs(row.date).add(1, 'day').format('YYYY-MM-DD')
- nextWeek = calculateWeek(nextDate)
- }
- // 创建新行,复制所有属性
- const newRow: ScheduleRow = {
- ...row,
- sourceIndex: row.index,
- date: nextDate, // 设置为下一天
- week: nextWeek, // 设置对应的星期
- isCopied: true, // 标记为复制的行
- submitted: false, // 标记为未提交
- modified: true, // 标记为已修改
- // 清空检验员相关数据
- checkers: [],
- teamList: [],
- inspectors: [],
- // 深拷贝其他数组类型字段
- pipeMedium: row.pipeMedium ? [...row.pipeMedium] : []
- }
- // 找到源行的索引
- const sourceIndex = tableData.value.findIndex(r => r.id === row.id)
- // 将新行插入到源行后面
- if (sourceIndex !== -1) {
- // 设置新行的索引为源行索引 + 1
- newRow.index = sourceIndex + 1
- tableData.value.splice(sourceIndex + 1, 0, newRow)
- // 更新后续行的索引
- for (let i = sourceIndex + 2; i < tableData.value.length; i++) {
- tableData.value[i].index = i
- }
- } else {
- // 如果找不到源行,将新行添加到末尾
- newRow.index = tableData.value.length
- tableData.value.push(newRow)
- }
- ElMessage.success('复制成功,日期已自动设为下一天,请修改检验员后提交')
- }
- const handleQuery = async () => {
- loading.value = true
- const res = await EquipPipeSchedulingApi.planSchedulingShiftSchedule(queryParams.value)
- // 处理后端返回的null值
- tableData.value = (res || []).map((item, index) => ({
- ...item,
- index,
- date: item.date ? dayjs(item.date).format('YYYY-MM-DD') : '',
- week: item.week || '',
- checkers: item.checkers || [],
- teamList: item.teamList || [],
- checkType: item.checkType || '',
- unitName: item.unitName || '',
- pipeAddress: item.pipeAddress || '',
- contact: item.contact || '',
- contactPhone: item.contactPhone || '',
- pipeMedium: item.pipeMedium || [],
- pipeLengthTotal: item.pipeLengthTotal || '',
- equipDistrictName: item.equipDistrictName || '',
- equipStreetName: item.equipStreetName || '',
- lastLegalPeriodicalInspectionReportNo: item.lastLegalPeriodicalInspectionReportNo || '',
- lastYearReportNo: item.lastYearReportNo || '',
- lastMaintenanceReportNo: item.lastMaintenanceReportNo || '',
- confirmOrderId: item.confirmOrderId || '',
- status: item.status,
- isCopied: false,
- submitted: true
- }))
- tableData.value.forEach((row, index) => {
- const inspectors = row.teamList?.flatMap(team => {
- const teamMembers = []
- // 处理组长
- if (team.leaders && team.leaders.length > 0) {
- team.leaders.forEach(leader => {
- if (leader) {
- teamMembers.push({
- memberId: leader.id,
- groupTeamId: team.groupTeamId,
- leaderId: leader.id,
- member: leader,
- isLeader: true
- })
- }
- })
- }
- // 处理组员
- if (team.members && team.members.length > 0) {
- team.members.forEach(member => {
- if (member) {
- teamMembers.push({
- memberId: member.id,
- groupTeamId: team.groupTeamId,
- leaderId: team.leaders?.[0]?.id || '',
- member: member,
- isLeader: false
- })
- }
- })
- }
- return teamMembers
- }) || []
- row.inspectors = inspectors
- console.log('inspectors', inspectors)
- })
- loading.value = false
- }
- // 自动保存单行:修改日期或检验员后实时保存
- // 前提:日期不重复 + 检验员不为空
- const autoSaveRow = async (row: ScheduleRow) => {
- // 校验:日期不能为空
- if (!row.date || row.date.trim() === '') {
- return
- }
- // 校验:检验员不能为空
- if (!row.checkers || row.checkers.length === 0) {
- return
- }
- // 校验:同 confirmOrderId 日期不能重复
- if (row.confirmOrderId) {
- const sameGroup = tableData.value.filter(r => r.confirmOrderId === row.confirmOrderId)
- const duplicate = sameGroup.some(item => item.date === row.date && item !== row)
- if (duplicate) {
- ElMessage.warning('同一个约检确认单下日期不能重复')
- return
- }
- }
- try {
- const teamList = (row.teamList || []).map(team => ({
- groupTeamId: team.groupTeamId,
- leaderId: team.leaders?.[0]?.id || '',
- memberIdList: team.members?.map(member => member.id) || []
- }))
- if (row.isCopied && !row.submitted) {
- // 复制行
- await EquipPipeSchedulingApi.setShiftSchedule([{
- isCopy: true,
- sourceId: row.id,
- date: row.date,
- teamList: teamList
- }])
- row.submitted = true
- row.modified = false
- } else {
- // 修改行
- await EquipPipeSchedulingApi.setShiftSchedule([{
- isCopy: false,
- id: row.id,
- date: row.date,
- teamList: teamList
- }])
- row.modified = false
- }
- ElMessage.success('保存成功')
- } catch (error) {
- console.error('自动保存失败:', error)
- ElMessage.error('保存失败')
- }
- }
- // 提交计划 - 提交勾选的行
- const handleSubmitSelected = async () => {
- if (selectedRows.value.length === 0) {
- ElMessage.warning('请先勾选需要提交的计划')
- return
- }
- const taskIdsToSubmit: any[] = []
- selectedRows.value.forEach(row => {
- taskIdsToSubmit.push(
- row.id
- )
- })
- try {
- await ElMessageBox.confirm(
- `是否确认提交选中的这${taskIdsToSubmit.length} 个计划?`,
- '提示',
- {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }
- )
- await EquipPipeSchedulingApi.planSchedulingConfirm({
- ids: taskIdsToSubmit
- })
- ElMessage.success('提交计划成功')
- // 提交成功后清空选中状态
- selectedRows.value = []
- // 重新加载数据
- handleQuery()
- } catch (error) {
- console.error('提交计划失败:', error)
- ElMessage.error('提交计划失败')
- }
- }
- // 查询
- // 当前行变化(单选)
- const handleCurrentChange = (currentRow: ScheduleRow | null) => {
- if (currentRow) {
- selectedRows.value = [currentRow]
- } else {
- selectedRows.value = []
- }
- }
- // 排序变化
- const handleSortChange = ({ column, prop, order }: { column: any; prop: string; order: string }) => {
- if (order) {
- sortOrderBy.value = prop
- sortOrderType.value = order === 'ascending' ? 'asc' : 'desc'
- } else {
- sortOrderBy.value = ''
- sortOrderType.value = ''
- }
- handleQuery()
- }
- // 导出排班表 - 导出和列表看到的数据一模一样
- const handleExport = async () => {
- try {
- exportLoading.value = true
- const data = await EquipPipeSchedulingApi.exportShiftSchedule(queryParams.value)
- // 使用 Blob 方式下载
- const blob = new Blob([data], { type: 'application/vnd.ms-excel' })
- const href = URL.createObjectURL(blob)
- const downA = document.createElement('a')
- downA.href = href
- downA.download = '排班表'
- downA.click()
- URL.revokeObjectURL(href)
- ElMessage.success('导出成功')
- } catch (error) {
- console.error('导出失败:', error)
- ElMessage.error('导出失败')
- } finally {
- exportLoading.value = false
- }
- }
- // 暴露方法给父组件
- defineExpose({
- handleQuery,
- handleSubmitSelected,
- handleExport
- })
- // ==================== 生命周期 ====================
- onMounted(async () => {
- await handleQuery()
- })
- </script>
- <style scoped lang="scss">
- .shift-schedule-container {
- margin-top: 15px;
- .shift-schedule-table {
- :deep(.el-table__header th) {
- background-color: #e5f0fb;
- color: #0a2c48;
- font-weight: 600;
- font-size: 13px;
- text-transform: uppercase;
- letter-spacing: 0.3px;
- }
- :deep(.el-table__header th:first-child) {
- font-weight: 600;
- color: #113355;
- border-left: 3px solid #3f78b3;
- }
- :deep(.el-table__row td) {
- padding: 10px 6px;
- font-size: 13px;
- background-color: #ffffff;
- }
- // 当前选中行高亮
- :deep(.el-table__row.current-row) {
- background-color: #ecf5ff !important;
- td {
- background-color: #ecf5ff !important;
- }
- }
- // 复制的行高亮显示
- :deep(.el-table__row.copied-row) {
- background-color: #fff3cd !important;
- td {
- background-color: #fff3cd !important;
- }
- }
- // 修改的行高亮显示
- :deep(.el-table__row.modified-row) {
- background-color: #e7f3ff !important;
- td {
- background-color: #e7f3ff !important;
- }
- }
- :deep(.el-table__row td:first-child) {
- font-weight: 600;
- color: #113355;
- border-left: 3px solid #3f78b3;
- }
- // 日期单元格基础样式
- :deep(.date-cell) {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- .edit-icon {
- cursor: pointer;
- color: #409eff;
- font-size: 14px;
- transition: all 0.3s;
- &:hover {
- color: #66b1ff;
- transform: scale(1.2);
- }
- }
- }
- // 已修改的日期单元格样式
- :deep(.modified-cell.date-cell) {
- background-color: #fff3cd;
- padding: 4px 0;
- border-radius: 4px;
- box-shadow: 0 0 0 1px #ffc107 inset !important;
- }
- // 已修改的检验员单元格样式
- :deep(.modified-checker-cell) {
- .checker-trigger {
- background-color: #fff3cd !important;
- box-shadow: 0 0 0 1px #ffc107 inset !important;
- }
- }
- // 检验员显示样式
- .checker-display {
- padding: 4px 8px;
- min-height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- color: #606266;
- font-size: 13px;
- }
- // 检验员触发器样式
- .checker-trigger {
- padding: 4px 8px;
- min-height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- border-radius: 4px;
- transition: all 0.3s;
- color: #909399;
- &:hover {
- background-color: #f5f7fa;
- color: #409eff;
- }
- &.has-checkers {
- color: #409eff;
- font-weight: 500;
- }
- .checker-text {
- flex: 1;
- text-align: center;
- overflow: visible;
- text-overflow: clip;
- white-space: normal;
- word-break: break-word;
- line-height: 1.6;
- max-width: 280px;
- }
- .edit-icon {
- font-size: 14px;
- opacity: 0.6;
- flex-shrink: 0;
- margin-left: 4px;
- }
- }
- // Popover内容样式
- .popover-content {
- max-height: 400px;
- overflow-y: auto;
- padding: 8px;
- }
- :deep(.dialog-footer) {
- display: flex;
- justify-content: flex-end;
- gap: 10px;
- }
- }
- }
- // 状态图例样式(用于tooltip)
- .status-legend {
- .legend-item {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 4px 0;
- font-size: 13px;
- color: #fff;
- .status-dot {
- display: inline-block;
- width: 10px;
- height: 10px;
- border-radius: 50%;
- flex-shrink: 0;
- }
- }
- }
- // 状态颜色类
- .dot-scheduled {
- background: #409eff;
- }
- .dot-pending-appointment {
- background: #e6a23c;
- }
- .dot-accepted {
- background: #67c23a;
- }
- .dot-testing {
- background: #f56c6c;
- }
- </style>
- <style lang="scss">
- // Popover 全局样式(不使用scoped)
- .checker-select-popover {
- padding: 0 !important;
- max-height: 500px;
- overflow: hidden;
- .el-popover__title {
- padding: 12px 16px;
- margin: 0;
- border-bottom: 1px solid #EBEEF5;
- font-weight: 600;
- color: #303133;
- }
- // 确保 CheckerSelect 组件的样式正确
- .checker-select-container {
- .checker-list {
- border: none;
- max-height: 450px;
- overflow-y: auto;
- }
- }
- }
- </style>
|