zjk
2026-06-24 e0bef82217ad863d59bba5cb660bff09adf02208
fix: 修改样式问题
5个文件已修改
193 ■■■■■ 已修改文件
src/views/operations/attendance/shift/components/ShiftFormModal.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/attendance/statistics/detail.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/personnel/safetyOfficerInfo/index.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/taskOrder/pendingReassignment/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/transaction/pricingManagement/detail.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/attendance/shift/components/ShiftFormModal.vue
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, nextTick, ref, watch } from 'vue'
import type { FormInst, FormRules } from 'naive-ui'
interface FormModel {
@@ -37,6 +37,7 @@
})
const formRef = ref<FormInst | null>(null)
const showRestTimeSection = ref(false)
const formModel = ref<FormModel>({
  shiftName: '',
  startTime: null,
@@ -163,6 +164,26 @@
  }
}
watch(
  [() => show.value, () => formModel.value.isRest],
  async ([modalVisible, isRest]) => {
    if (!modalVisible || !isRest) {
      showRestTimeSection.value = false
      if (!isRest) {
        // 关闭中途休息时清空时间,避免旧值残留
        formModel.value.restStartTime = null
        formModel.value.restEndTime = null
      }
      return
    }
    // 等弹窗可见后再挂载时间组件,避免动态渲染异常
    await nextTick()
    showRestTimeSection.value = true
  },
  { immediate: true },
)
function openEdit(data: any) {
  formModel.value = {
    ...formModel.value,
@@ -285,7 +306,7 @@
        <n-switch v-model:value="formModel.isRest" />
      </n-form-item>
      <div v-if="formModel.isRest" class="grid grid-cols-3 gap-x-24px">
      <div v-if="showRestTimeSection" class="grid grid-cols-3 gap-x-24px">
        <n-form-item label="开始休息时间" path="restStartTime">
          <n-time-picker
            v-model:formatted-value="formModel.restStartTime"
src/views/operations/attendance/statistics/detail.vue
@@ -1,11 +1,11 @@
<script setup lang="tsx">
import noDataImg from '@/assets/element-img/no-data.png'
import { ref, computed } from 'vue'
import { computed, ref } from 'vue'
import { useBoolean } from '@/hooks'
import { useRoute } from 'vue-router'
import type { DataTableColumns } from 'naive-ui'
import { NTag } from 'naive-ui'
import { getClockInStatisticsDetailList, exportClockInStatisticsDetails } from '@/service/api/attendance'
import { exportClockInStatisticsDetails, getClockInStatisticsDetailList } from '@/service/api/attendance'
import { downloadFile } from '@/utils'
import SearchPanel from '@/components/custom/SearchPanel.vue'
import dayjs from 'dayjs'
@@ -16,7 +16,7 @@
const searchModel = ref({
  appUserId: null as any,
  statisticDate: null as [number, number] | null
  statisticDate: null as [number, number] | null,
})
// 统计数据
@@ -24,7 +24,7 @@
  shouldClockInDays: '',
  clockInDays: '',
  notClockInDays: '',
  lateEarly: ''
  lateEarly: '',
})
const detailList = ref<any[]>([])
@@ -35,10 +35,10 @@
  pageSize: 10,
})
const handleReset = () => {
function handleReset() {
  searchModel.value = {
    appUserId: route.params.id,
    statisticDate: null
    statisticDate: null,
  }
  handleSearch()
}
@@ -47,7 +47,7 @@
  getList()
}
const handleExport = async () => {
async function handleExport() {
  const params = {
    ...pageParams.value,
    appUserId: searchModel.value.appUserId,
@@ -64,54 +64,79 @@
  {
    label: '打卡日期',
    path: 'statisticDate',
    render: () => <n-date-picker style="width: 280px" actions={[]} close-on-select={true} v-model:value={searchModel.value.statisticDate} format="yyyy/MM/dd" type="daterange" clearable start-placeholder="开始时间" end-placeholder="结束时间" />
  }
    render: () => <n-date-picker style="width: 280px" actions={[]} close-on-select={true} v-model:value={searchModel.value.statisticDate} format="yyyy/MM/dd" type="daterange" clearable start-placeholder="开始时间" end-placeholder="结束时间" />,
  },
])
const getResultTagType = (result: string) => {
  if (result === '正常') return 'primary'
  if (result === '迟到') return 'warning'
  if (result === '缺卡') return 'error'
  if (result === '早退') return 'warning'
function getResultTagType(result: string) {
  if (result === '正常')
    return 'primary'
  if (result === '迟到')
    return 'warning'
  if (result === '缺卡')
    return 'error'
  if (result === '早退')
    return 'warning'
  return 'default'
}
const columns = computed<DataTableColumns<any>>(() => [
  { title: '序号', key: 'serialNumber', width: 60, align: 'left', resizable: true, fixed: 'left' },
  { title: '操作人', key: 'name', width: 120, align: 'left', resizable: true, fixed: 'left'  },
  { title: '角色', key: 'roleName', width: 120, align: 'left', resizable: true,
     render: row => <span style="padding:2px 8px;background-color: #E6F4FF;color:#0068FF;border-radius: 4px;">{row.roleName}</span>
   },
  { title: '所属队伍', key: 'teamName', width: 120, align: 'left', resizable: true, },
  { title: '操作人', key: 'name', width: 120, align: 'left', resizable: true, fixed: 'left' },
  {
    title: '角色',
    key: 'roleName',
    width: 140,
    align: 'left',
    resizable: true,
    render: (row) => {
      const roleNames = String(row.roleName || '')
        .split(';')
        .map((item: string) => item.trim())
        .filter(Boolean)
      if (!roleNames.length)
        return '-'
      return (
        <div class="flex flex-wrap gap-6px">
          {roleNames.map((roleName: string) => (
            <NTag type="primary" bordered={false} size="small" style={{ borderRadius: '4px' }}>
              {roleName}
            </NTag>
          ))}
        </div>
      )
    },
  },
  { title: '所属队伍', key: 'teamName', width: 120, align: 'left', resizable: true },
  {
    title: '日期',
    key: 'clockTime',
    width: 100,
    align: 'left',
    resizable: true,
    render: row => row.clockTime ? dayjs(row.clockTime).format('YYYY/MM/DD ') : ''
    render: row => row.clockTime ? dayjs(row.clockTime).format('YYYY/MM/DD ') : '',
  },
  { title: '班次', key: 'shiftName', width: 190, align: 'left', resizable: true,
    render: (row) => {
      return h('span', {
        style: {
          display: 'inline-block',
          padding: '2px 12px',
          borderRadius: '4px',
          fontSize: '12px',
          backgroundColor: row.shiftColor,
          color: 'rgba(23, 31, 38, 0.8)',
        },
      }, row.shiftName)
    },
   },
  { title: '班次', key: 'shiftName', width: 190, align: 'left', resizable: true, render: (row) => {
    return h('span', {
      style: {
        display: 'inline-block',
        padding: '2px 12px',
        borderRadius: '4px',
        fontSize: '12px',
        backgroundColor: row.shiftColor,
        color: 'rgba(23, 31, 38, 0.8)',
      },
    }, row.shiftName)
  } },
  {
    title: '上班打卡时间',
    key: 'clockInTime',
    width: 170,
    align: 'left',
    resizable: true,
    render: row => row.clockInTime ? dayjs(row.clockInTime).format('YYYY/MM/DD HH:mm') : ''
    render: row => row.clockInTime ? dayjs(row.clockInTime).format('YYYY/MM/DD HH:mm') : '',
  },
  {
    title: '下班打卡时间',
@@ -119,7 +144,7 @@
    width: 170,
    align: 'left',
    resizable: true,
    render: row => row.clockOutTime ? dayjs(row.clockOutTime).format('YYYY/MM/DD HH:mm') : ''
    render: row => row.clockOutTime ? dayjs(row.clockOutTime).format('YYYY/MM/DD HH:mm') : '',
  },
  {
    title: '上班打卡结果',
@@ -128,15 +153,16 @@
    align: 'left',
    resizable: true,
    render: (row) => {
      if (!row.clockInResult) return ''
      if (!row.clockInResult)
        return ''
      return (
        <NTag type={getResultTagType(row.clockInResult)} size="small" bordered={false}>
          {row.clockInResult}
        </NTag>
      )
    }
    },
  },
  {
    title: '下班打卡结果',
    key: 'clockOutResult',
@@ -144,15 +170,16 @@
    align: 'left',
    resizable: true,
    render: (row) => {
      if (!row.clockOutResult) return ''
      if (!row.clockOutResult)
        return ''
      return (
        <NTag type={getResultTagType(row.clockOutResult)} size="small" bordered={false}>
          {row.clockOutResult}
        </NTag>
      )
    }
    },
  },
  { title: '打卡地址', key: 'clockInLocation', width: 320, align: 'left', ellipsis: { tooltip: true }}
  { title: '打卡地址', key: 'clockInLocation', width: 320, align: 'left', ellipsis: { tooltip: true } },
])
async function getList() {
@@ -200,8 +227,12 @@
            </n-form-item>
          </n-gi>
          <template #action>
            <n-button style="width: 84px; height: 32px" @click="handleReset">重置</n-button>
            <n-button type="primary" style="width: 84px; height: 32px" @click="handleSearch">查询</n-button>
            <n-button style="width: 84px; height: 32px" @click="handleReset">
              重置
            </n-button>
            <n-button type="primary" style="width: 84px; height: 32px" @click="handleSearch">
              查询
            </n-button>
          </template>
        </SearchPanel>
      </n-form>
@@ -219,15 +250,18 @@
          <div class="flex gap-2">
            <n-button
              style="width: 100px; height: 32px;"
              @click="handleExport">
              @click="handleExport"
            >
              导出打卡明细
            </n-button>
          </div>
        </n-flex>
      </template>
      <div class="flex-1 flex flex-col h-full">
        <n-data-table :columns="columns" :data="detailList" :loading="loading" :bordered="false" :header-height="18"
          :row-height="18" :scroll-x="1510" class="flex-1">
        <n-data-table
          :columns="columns" :data="detailList" :loading="loading" :bordered="false" :header-height="18"
          :row-height="18" :scroll-x="1510" class="flex-1" flex-height
        >
          <template #empty>
            <div class="flex-center">
              <img :src="noDataImg" style="width:123px;height:125px" @error="(e: any) => { e.target.src = 'https://huishou-1323682843.cos.ap-nanjing.myqcloud.com/images/9bed493b-a6aa-4ef6-ac10-7f67f5c6adc5.png' }">
src/views/operations/personnel/safetyOfficerInfo/index.vue
@@ -3,7 +3,7 @@
import type { DataTableColumns } from 'naive-ui'
import { computed, onActivated, onMounted, ref } from 'vue'
import dayjs from 'dayjs'
import { NButton, NTag, useDialog } from 'naive-ui'
import { NButton, NSwitch, NTag, useDialog } from 'naive-ui'
import { useBoolean } from '@/hooks'
import { useRouter } from 'vue-router'
import SearchPanel from '@/components/custom/SearchPanel.vue'
@@ -236,7 +236,7 @@
async function handleToggleStatus(row: SafetyOfficerItem) {
  const nextStatus = row.status === 1 ? 0 : 1
  const actionText = nextStatus === 1 ? '停用' : '启用'
  const actionText = nextStatus === 1 ? '启用' : '停用'
  dialog.warning({
    title: `是否确认${actionText}该安全员?`,
    content: ``,
@@ -438,9 +438,16 @@
        <NButton text v-permission="2026061540" type="primary" onClick={() => handleEdit(row)}>
          编辑
        </NButton>
        <NButton text v-permission="2026061541" type="primary" onClick={() => handleToggleStatus(row)}>
          {row.status === 1 ? '停用' : '启用'}
        </NButton>
        <NSwitch
          v-permission="2026061541"
          value={row.status === 1}
          onUpdateValue={() => handleToggleStatus(row)}
        >
          {{
            checked: () => '停用',
            unchecked: () => '启用',
          }}
        </NSwitch>
      </n-space>
    ),
  },
src/views/operations/taskOrder/pendingReassignment/index.vue
@@ -371,6 +371,9 @@
    width: 100,
    resizable: true,
    render(row) {
      if (!row.taskUrgencyLevel) {
        return '-'
      }
      const option = taskUrgencyLevelOptions.find(item => item.value === row.taskUrgencyLevel)
      return (
        <n-tag type={option?.type || 'default'} bordered={false}>
src/views/transaction/pricingManagement/detail.vue
@@ -1042,7 +1042,7 @@
                        v-model:value="model.basicPricingJson1.waitFeeEnabled"
                        :checked-value="1"
                        :unchecked-value="0"
                        class="ml-8px"
                        class="ml-8px font-400! text-13px!"
                      >
                        <template #checked>
                          启用
@@ -1080,7 +1080,7 @@
                        v-model:value="model.basicPricingJson1.longDistanceFeeEnabled"
                        :checked-value="1"
                        :unchecked-value="0"
                        class="ml-8px"
                        class="ml-8px font-400! text-13px!"
                      >
                        <template #checked>
                          启用
@@ -1168,7 +1168,7 @@
                        v-model:value="model.basicPricingJson1.nightFeeEnabled"
                        :checked-value="1"
                        :unchecked-value="0"
                        class="ml-8px"
                        class="ml-8px font-400! text-13px!"
                      >
                        <template #checked>
                          启用
@@ -1254,7 +1254,7 @@
                        v-model:value="model.basicPricingJson1.peakFeeEnabled"
                        :checked-value="1"
                        :unchecked-value="0"
                        class="ml-8px"
                        class="ml-8px font-400! text-13px!"
                      >
                        <template #checked>
                          启用
@@ -1349,7 +1349,7 @@
                        v-model:value="model.basicPricingJson1.holidayFeeEnabled"
                        :checked-value="1"
                        :unchecked-value="0"
                        class="ml-8px"
                        class="ml-8px font-400! text-13px!"
                      >
                        <template #checked>
                          启用
@@ -1450,7 +1450,7 @@
                        v-model:value="model.dynamicPricingJson.supplyDemandEnabled"
                        :checked-value="1"
                        :unchecked-value="0"
                        class="ml-8px"
                        class="ml-8px font-400! text-13px!"
                      >
                        <template #checked>
                          启用
@@ -1517,7 +1517,7 @@
                        v-model:value="model.dynamicPricingJson.congestionEnabled"
                        :checked-value="1"
                        :unchecked-value="0"
                        class="ml-8px"
                        class="ml-8px font-400! text-13px!"
                      >
                        <template #checked>
                          启用
@@ -1564,7 +1564,7 @@
                        v-model:value="model.dynamicPricingJson.weatherEnabled"
                        :checked-value="1"
                        :unchecked-value="0"
                        class="ml-8px"
                        class="ml-8px font-400! text-13px!"
                      >
                        <template #checked>
                          启用
@@ -2060,4 +2060,8 @@
  box-shadow: 0px 0px 5px 0px rgba(23, 31, 38, 0.05);
  padding: 16px 24px;
}
:deep(.n-switch:focus .n-switch__rail) {
  box-shadow: none;
}
</style>