吉安感知网项目-前端
chenyao
2026-01-22 9952463a23b48ffe407d6dd2d3d78218c40ec8de
feat:更新工单
5 files modified
799 ■■■■■ changed files
applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue 18 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue 13 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue 341 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue 324 ●●●●● patch | view | raw | blame | history
uniapps/work-wx/src/subPackages/regulationsDetail/details.vue 103 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
@@ -1,8 +1,8 @@
<template>
    <el-dialog class="gd-dialog" :close-on-click-modal="false" v-model="visible" title="查看" @closed="visible = false" width="1000px" destroy-on-close>
        <div class="" v-loading="loading">
            <div class="gd-table-content-bg">
                <el-table :data="list">
    <el-dialog class="gd-dialog" v-model="visible" title="查看" @closed="visible = false" width="1000px" destroy-on-close>
        <div class="gd-table-container" v-loading="loading" style="height: 600px">
            <div class="gd-table-content gd-table-content-bg">
                <el-table class="gd-table" :data="list">
                    <el-table-column label="线索缩略图" width="120">
                        <template v-slot="{ row }">
                            <el-image
@@ -32,9 +32,10 @@
                    <el-table-column prop="distributeUserName" show-overflow-tooltip label="分发人员" />
                    <el-table-column label="操作" class-name="operation-btns" width="140">
                        <template v-slot="{ row }">
                            <el-link @click="openDistributeDialog(row)" :disabled="row.distributeStatus === 1">
                            <el-link v-if="row.distributeStatus === 0" @click="openDistributeDialog(row)" :disabled="row.distributeStatus === 1">
                                转为事件并分发
                            </el-link>
                            <div class="disabled-text" v-else>转为事件并分发</div>
                        </template>
                    </el-table-column>
                </el-table>
@@ -119,4 +120,9 @@
defineExpose({ open })
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
    .disabled-text {
        color: #C0C4CC;
        cursor: not-allowed;
    }
</style>
applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue
@@ -1,7 +1,8 @@
<!-- 线索事件管理 -->
<template>
    <basic-container>
        <el-form ref="queryParamsRef" :model="searchParams" class="gd-search-form">
            <el-form-item label="任务名称" prop="patrolTaskName">
            <el-form-item label="模糊搜索" prop="patrolTaskName">
                <el-input
                    class="gd-input"
                    v-model="searchParams.patrolTaskName"
@@ -11,7 +12,7 @@
                />
            </el-form-item>
            <el-form-item label="任务类型" prop="patrolTaskType">
            <el-form-item label="巡查任务类型" prop="patrolTaskType">
                <el-select
                    class="gd-select"
                    popper-class="gd-select-popper"
@@ -29,7 +30,7 @@
                </el-select>
            </el-form-item>
            <el-form-item label="任务状态" prop="taskStatus">
            <!-- <el-form-item label="任务状态" prop="taskStatus">
                <el-select
                    class="gd-select"
                    popper-class="gd-select-popper"
@@ -45,7 +46,7 @@
                        :value="item.dictKey"
                    />
                </el-select>
            </el-form-item>
            </el-form-item> -->
            <el-form-item label="执行时间" prop="executeTime">
                <el-date-picker
@@ -86,10 +87,12 @@
                    <el-table-column prop="executeTime" show-overflow-tooltip label="任务执行时间" />
                    <el-table-column prop="workOrderName" show-overflow-tooltip label="关联工单" />
                    <el-table-column prop="createTime" show-overflow-tooltip label="巡查任务创建时间" />
                    <el-table-column prop="resultCount" show-overflow-tooltip label="线索数量" />
                    <el-table-column prop="issueEventCount" show-overflow-tooltip label="转为问题" />
                    <el-table-column prop="taskDesc" show-overflow-tooltip label="巡查任务描述" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="viewDiaLogView(row)">查看</el-link>
                            <el-link @click="viewDiaLogView(row)">查看线索</el-link>
                        </template>
                    </el-table-column>
                </el-table>
applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue
@@ -1,9 +1,348 @@
<!-- 巡查报告管理 -->
<template>
  <basic-container>
    基础管理
    <el-form ref="queryParamsRef" :model="searchParams" class="gd-search-form">
            <el-form-item label="模糊搜索" prop="nickName">
                <el-input
                    class="gd-input"
                    v-model="searchParams.nickName"
                    placeholder="请输入"
                    clearable
                    @clear="handleSearch"
                />
            </el-form-item>
            <el-form-item label="文档类型" prop="resultType">
                <el-select
                    class="gd-select"
                    popper-class="gd-select-popper"
                    v-model="searchParams.resultType"
                    placeholder="请选择"
                    clearable
                    @change="handleSearch"
                >
                    <el-option
                        v-for="item in dictObj.patrolTaskType"
                        :key="item.dictKey"
                        :label="item.dictValue"
                        :value="item.dictKey"
                    />
                </el-select>
            </el-form-item>
            <el-form-item class="gd-search-actions">
                <el-button :icon="RefreshRight" @click="resetForm"></el-button>
                <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button>
            </el-form-item>
        </el-form>
        <div class="gd-table-toolbar">
      <el-button :icon="Download" color="#4C34FF" type="primary" @click="handleDownload">文档下载</el-button>
            <el-button :icon="Upload" color="#4C34FF" type="primary" @click="handleUpload">文档上传</el-button>
        </div>
    <div class="gd-table-container" v-loading="loading">
            <div class="gd-table-content gd-table-content-bg">
                <el-table class="gd-table" :data="list" @selection-change="handleSelectionChange">
                    <el-table-column type="selection" width="46" />
                    <el-table-column type="index" width="64" label="序号" />
                    <el-table-column prop="nickName" show-overflow-tooltip label="文档名称" />
                    <el-table-column prop="attachSize" show-overflow-tooltip label="文档大小" />
                    <el-table-column prop="deptName" show-overflow-tooltip label="文档归属" />
                    <!-- <el-table-column prop="resultType" show-overflow-tooltip label="文档类型" /> -->
                     <el-table-column prop="resultType" show-overflow-tooltip label="文档类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.resultType, dictObj.patrolTaskType) }}
                        </template>
                    </el-table-column>
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="seeOnlineWord(item)">查看</el-link>
                            <el-link @click="openForm(row)">在线编辑</el-link>
                            <el-link @click="handleDelete(row)">删除</el-link>
                        </template>
                    </el-table-column>
                </el-table>
            </div>
            <div class="gd-pagination-parent">
                <el-pagination
                    popper-class="gd-select-popper"
                    v-model:current-page="searchParams.current"
                    v-model:page-size="searchParams.size"
                    layout="total, prev, pager, next, sizes"
                    :total="total"
                    @change="getList"
                />
            </div>
        </div>
    <el-dialog class="gd-dialog" append-to-body v-model="isShowEditView" :title="titleTxt"
        :width="pxToRem(800)" :close-on-click-modal="false" :destroy-on-close="true" @close="handleClose">
      <el-form class="gd-dialog-form" ref="ruleFormRef" :model="editParams" :rules="rules" label-width="140px">
        <el-form-item label="文档名称" prop="nickName">
          <el-input v-model="editParams.nickName" />
        </el-form-item>
        <el-form-item label="文档类型" prop="resultType" v-if="titleTxt === '上传巡查报告'">
          <el-select
                    class="gd-select"
                    popper-class="gd-select-popper"
                    v-model="editParams.resultType"
                    placeholder="请选择"
                    clearable
                >
                    <el-option
                        v-for="item in dictObj.patrolTaskType"
                        :key="item.dictKey"
                        :label="item.dictValue"
                        :value="item.dictKey"
                    />
                </el-select>
        </el-form-item>
        <el-form-item label="上传文件" prop="link" v-if="titleTxt === '上传巡查报告'">
            {{ uploadName }}
          <el-upload
            class="avatar-uploader"
            action=""
            :show-file-list="false"
            :before-upload="onUploadFileBefore"
          >
            <el-button size="small" type="primary">点击上传</el-button>
          </el-upload>
        </el-form-item>
      </el-form>
    <!-- </div> -->
     <template #footer>
            <el-button color="#F2F3F5" @click="isShowEditView = false">取消</el-button>
            <el-button class="save-btn" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="submit(ruleFormRef)">
                保存
            </el-button>
        </template>
    </el-dialog>
    <PreviewFiles v-model="previewVisible" :src="searchUrl" type="docx"/>
    <el-image v-if="previewVisibleImg" :src="searchUrl" fit="contain" style="height: 100%;width: 100%" />
  </basic-container>
</template>
<script setup>
  import { Search, RefreshRight, Download, Upload, Delete } from '@element-plus/icons-vue'
  import { fjPageApi, fjSubmitApi, fjRemoveApi, fjDetailApi, fjUploadApi } from './inspectionRequestApi'
  import { useStore } from 'vuex'
  import { ref, computed, inject, onMounted } from 'vue'
  import { ElMessage, ElMessageBox } from 'element-plus'
  import { getDictLabel } from '@ztzf/utils'
  import PreviewFiles from '@/components/PreviewFiles/PreviewFiles.vue'
  import { getDictionaryByCode } from '@/api/system/dictbiz'
  const store = useStore()
  const userInfo = computed(() => store.getters.userInfo);
  // 初始化查询参数
const initSearchParams = () => ({
    nickName: '',
    resultType: '',
    current: 1, // 当前页
    size: 10, // 每页大小
})
// 查看文档
const previewVisible = ref(false)
const previewVisibleImg = ref(false)
const searchUrl = ref('')
// 上传名称
const uploadName = ref('')
const dictObj = ref({
    patrolTaskType: [], // 巡查任务类型
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的ID列表
const selectedFiles = ref([]) // 勾选的文件列表
const queryParamsRef = ref(null) // 查询表单实例
const isShowEditView = ref(false)
const titleTxt = ref('上传巡查报告')
const editParams = ref({
  id:'',
  nickName: '',
  resultType: '',
  link: '',
})
const ruleFormRef = ref()
const submitting = ref(false)
const rules = ref({
  nickName: [{ required: true, message: '请输入文档名称', trigger: ['blur'] }],
  resultType: [{ required: true, message: '请选择文档类型', trigger: ['change'] }],
  link: [{ required: true, message: '请上传文件', trigger: ['change'] }],
})
// 获取字典
function getDictList() {
    getDictionaryByCode('patrolTaskType').then(res => {
        dictObj.value = res.data.data
    })
}
  // 获取列表
async function getList() {
    loading.value = true
    try {
        const res = await fjPageApi({ ...searchParams.value })
        console.log(res?.data?.data?.records,'888')
        list.value = res?.data?.data?.records ?? []
        console.log(list.value,'999')
        total.value = res?.data?.data?.total ?? 0
    } finally {
        loading.value = false
    }
}
// 重置查询
function resetForm() {
    queryParamsRef.value?.resetFields()
    searchParams.value.current = 1
    getList()
}
// 查询
function handleSearch() {
    searchParams.value.current = 1
    getList()
}
// 新增/编辑/查看 弹框
function openForm(row) {
    isShowEditView.value = true
      titleTxt.value = '编辑'
    editParams.value.id = row.id
    editParams.value.nickName = row.nickName
    editParams.value.resultType = row.resultType
    editParams.value.link = row.link
}
// 在线查看文档
function seeOnlineWord(item) {
    if (!item.link) {
        ElMessage.error('文档链接不存在')
        return
    } else if (!item.link.includes('docx') && !item.link.includes('pdf') && !item.link.includes('png') && !item.link.includes('jpg')) {
        ElMessage.error('可进行下载观看!')
        return
    } else if (item.link.includes('png') || item.link.includes('jpg')) {
        previewVisibleImg.value = true
        searchUrl.value = item.link
        return
    } else if (item.link.includes('docx') || item.link.includes('pdf')) {
        previewVisible.value = true
        searchUrl.value = item.link
        return
    }
}
// 删除
async function handleDelete(row) {
    const tips = row ? '该条' : '选中的项'
    await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', {
        type: 'warning',
        customClass: 'gd-confirm-custom',
        confirmButtonClass: 'gd-confirm-button',
        cancelButtonClass: 'gd-confirm-cancel-button',
    })
    const ids = row ? row.id : selectedIds.value.join(',')
    await fjRemoveApi({ ids })
    ElMessage.success('删除成功')
    selectedIds.value = []
    getList()
}
// 勾选值设置
function handleSelectionChange(rows) {
    selectedFiles.value = rows
    selectedIds.value = rows.map((item) => item.id)
}
// 文档下载
async function handleDownload() {
    // 如果是勾选一个可以直接下载,超过一个打包下载
    // 依次下载每个文件(添加延迟以避免浏览器限制)
    selectedFiles.value.forEach((file, index) => {
        setTimeout(() => {
            if (file.link) {
                const a = document.createElement('a')
                a.href = file.link
                a.download = file.originalName || `attachment_${index + 1}`
                document.body.appendChild(a)
                a.click()
                document.body.removeChild(a)
            }
        }, index * 300) // 300ms delay between downloads
    })
}
// 文档上传
async function handleUpload() {
    isShowEditView.value = true
      titleTxt.value = '上传巡查报告'
}
// 上传文件前处理
function onUploadFileBefore(file) {
  // 执行文件上传
  let data = new FormData();
  data.append('file', file);
  fjUploadApi(data).then(res => {
    if (res.data.code === 200) {
      ElMessage.success('上传成功')
      // 保存文件URL到表单
      uploadName.value = res.data.data.originalName
      editParams.value.link = res.data.data.link
    } else {
      ElMessage.error(res.msg || '上传失败')
    }
  })
  return false // 阻止组件的默认上传行为
}
// 保存上传文件数据
async function submit(formValidate) {
  if (!formValidate) return
  await formValidate.validate(async (valid, fields) => {
    if (valid) {
      submitting.value = true
      try {
         await fjSubmitApi({ ...editParams.value })
          ElMessage.success('保存成功')
          isShowEditView.value = false
          getList()
      } finally {
        submitting.value = false
      }
    }
  })
}
function handleClose() {
  // 清除表单内容
  uploadName.value = ''
  editParams.value = {
    id: '',
    nickName: '',
    resultType: '',
    uploadFile: '',
  }
}
onMounted(() => {
    getDictList()
    getList()
})
</script>
<style scoped lang="scss">
</style>
applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
@@ -1,9 +1,329 @@
<!-- 运营收益 -->
<template>
  <basic-container>
    基础管理
        <div class="gd-table-toolbar">
            <el-button :icon="Plus" color="#4C34FF" type="primary" @click="handleAdd">新增</el-button>
      <el-button :icon="Delete" color="#4C34FF" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
        </div>
   <div class="gd-table-container" v-loading="loading">
            <div class="gd-table-content gd-table-content-bg">
        <el-table class="gd-table" :data="tableList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="46" />
                <el-table-column label="序号" type="index" width="60"></el-table-column>
        <el-table-column prop="operatingIncome" label="营业收入" align="center"></el-table-column>
        <el-table-column prop="totalCost" label="综合总成本费用" align="center"></el-table-column>
        <el-table-column prop="netProfit" label="净利润" align="center"></el-table-column>
        <el-table-column prop="financialIrr" label="财务内部收益率" align="center"></el-table-column>
        <el-table-column prop="marketSpace" label="市场空间" align="center" show-overflow-tooltip></el-table-column>
        <el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
        <el-table-column prop="nickName" label="创建人" align="center"></el-table-column>
                <el-table-column label="操作" width="180" align="center">
                    <template #default="scope">
            <!-- <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button> -->
            <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
                        <el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
        </div>
    <div class="gd-pagination-parent">
                <el-pagination
                    popper-class="gd-select-popper"
                    v-model:current-page="params.current"
                    v-model:page-size="params.size"
                    layout="total, prev, pager, next, sizes"
                    :total="total"
                    @change="getList"
                />
            </div>
    </div>
  <el-dialog class="gd-dialog" append-to-body v-model="isShowEditView" :title="titleTxt"
        :width="pxToRem(800)" :close-on-click-modal="false" :destroy-on-close="true" @close="handleClose">
      <el-form class="gd-dialog-form" ref="ruleFormRef" :model="editParams" :rules="rules" label-width="140px">
        <el-form-item label="营业收入" prop="operatingIncome">
          <el-input v-model="editParams.operatingIncome" />
        </el-form-item>
        <el-form-item label="综合总成本费用" prop="totalCost">
          <el-input v-model="editParams.totalCost" />
        </el-form-item>
        <el-form-item label="净利润" prop="netProfit">
          <el-input v-model="editParams.netProfit" />
        </el-form-item>
        <el-form-item label="财务内部收益率" prop="financialIrr">
          <el-input v-model="editParams.financialIrr" />
        </el-form-item>
        <el-form-item label="市场空间" prop="marketSpace">
          <el-input v-model="editParams.marketSpace"  />
        </el-form-item>
      </el-form>
    <!-- </div> -->
     <template #footer>
            <el-button color="#F2F3F5" @click="isShowEditView = false">取消</el-button>
            <el-button class="save-btn" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="submit(ruleFormRef)">
                保存
            </el-button>
        </template>
    </el-dialog>
  </basic-container>
</template>
<script setup>
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import { operatingIncomePage, operatingIncomeUpdate, operatingIncomeAdd, operatingIncomeBatchDelete } from './operatingIncomeApi';
let titleTxt = ref('新增')
const total = ref(0)
const params = ref({
  current: 1,
  size: 10,
});
const submitting = ref(false)
const loading = ref(true) // 列表加载中
const selectedIds = ref([]) // 勾选的ID列表
let tableList = ref([])
let isShowEditView = ref(false)
const ruleFormRef = ref()
let editParams = ref({
  id: '',
  operatingIncome: '',
  totalCost: '',
  netProfit: '',
  financialIrr: '',
  marketSpace: '',
})
const rules = reactive({
  operatingIncome: [
    { required: true, message: '请输入营业收入', trigger: 'blur' },
    {
      validator: (rule, value, callback) => {
        if (!/^\d+(\.\d+)?$/.test(value)) {
          callback(new Error('请输入有效的数字(整数或小数)'));
        } else {
          callback();
        }
      },
      trigger: 'blur'
    }
  ],
  totalCost: [
    { required: true, message: '请输入综合总成本费用', trigger: 'blur' },
    {
      validator: (rule, value, callback) => {
        if (!/^\d+(\.\d+)?$/.test(value)) {
          callback(new Error('请输入有效的数字(整数或小数)'));
        } else {
          callback();
        }
      },
      trigger: 'blur'
    }
  ],
  netProfit: [
    { required: true, message: '请输入净利润', trigger: 'blur' },
    {
      validator: (rule, value, callback) => {
        if (!/^\d+(\.\d+)?$/.test(value)) {
          callback(new Error('请输入有效的数字(整数或小数)'));
        } else {
          callback();
        }
      },
      trigger: 'blur'
    }
  ],
  financialIrr: [
    { required: true, message: '请输入财务内部收益率', trigger: 'blur' },
    {
      validator: (rule, value, callback) => {
        if (!/^\d+(\.\d+)?$/.test(value)) {
          callback(new Error('请输入有效的数字(整数或小数)'));
        } else {
          callback();
        }
      },
      trigger: 'blur'
    }
  ],
  marketSpace: [
    { required: true, message: '请输入市场空间', trigger: 'blur' },
  ],
})
// 勾选值设置
function handleSelectionChange(rows) {
    selectedIds.value = rows.map(item => item.id)
}
function getList() {
  loading.value = true
  operatingIncomePage(params.value).then(res => {
    tableList.value = res.data.data.records || []
    total.value = res.data.data.total || 0
  }).finally(() => {
    loading.value = false
  })
}
function handleEdit(row) {
  titleTxt.value = '编辑'
  isShowEditView.value = true
  editParams.value = { ...row }
}
// 删除
async function handleDelete(row) {
    const tips = row ? '该条' : '选中的项'
    await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', {
        type: 'warning',
        customClass: 'gd-confirm-custom',
        confirmButtonClass: 'gd-confirm-button',
        cancelButtonClass: 'gd-confirm-cancel-button',
    })
    const ids = row ? row.id : selectedIds.value
    await operatingIncomeBatchDelete(ids)
    ElMessage.success('删除成功')
    selectedIds.value = []
    getList()
}
function handleAdd() {
  titleTxt.value = '新增'
  isShowEditView.value = true
}
async function submit(formValidate) {
  if (!formValidate) return
  await formValidate.validate((valid, fields) => {
    if (valid) {
      submitting.value = true
      try {
        if (titleTxt.value === '新增') {
          operatingIncomeAdd(editParams.value).then(res => {
            isShowEditView.value = false
            ElMessage.success('新增成功')
            getList()
          })
        } else {
          operatingIncomeUpdate(editParams.value).then(res => {
            isShowEditView.value = false
            ElMessage.success('操作成功')
            getList()
          })
        }
      } finally {
        submitting.value = false
      }
    }
  })
}
function handleClose() {
  // 清除表单内容
  editParams.value = {
    id: '',
    operating_income: '',
    total_cost: '',
    net_profit: '',
    financial_irr: '',
    market_space: '',
  }
}
onMounted(() => {
  getList()
})
</script>
<style scoped lang="scss">
<style lang="scss" scoped>
  .operatingIncome {
    height: 0;
    flex: 1;
    margin: 0 10px 10px 10px;
    background-color: #ffffff;
    padding: 10px 20px;
    border-radius: 5px;
    display: flex;
    flex-direction: column;
    .search-box {
      margin-top: 20px;
      height: 40px;
    }
    :deep(.el-input) {
      .el-input__wrapper {
        width: 200px;
      }
    }
    // 表格
    .mange-table {
      height: 0;
      flex: 1;
      margin-top: 18px;
      overflow: auto;
    }
    :deep(.el-pagination) {
      display: flex;
      justify-content: right;
    }
    :deep(.el-pagination button) {
      background: center center no-repeat none !important;
      color: #8eb8ea !important;
    }
    :deep(.ztzf-select){
      .el-select__selection {
        width: 200px;
      }
    }
  }
 .content {
  padding: 20px;
  .view-table {
    width: 100%;
    border-collapse: collapse;
    border: 1px solid #EBEEF5;
    tr {
      &:not(:last-child) {
        border-bottom: 1px solid #EBEEF5;
      }
      td {
        padding: 12px 10px;
        &.label {
          width: 140px;
          text-align: right;
          // color: #909399;
          // background-color: #F5F7FA;
          border-right: 1px solid #EBEEF5;
        }
        &.value {
          width: 180px;
          // color: #303133;
        }
      }
    }
  }
}
.content-edit {
  .el-form {
    .el-form-item {
      width: 320px;
      :deep(.el-form-item__label) {
        width: 140px;
      }
    }
    // .el-form-item:last-child {
    //   width: 640px;
    // }
    .btns {
        display: flex;
        justify-content: center
      }
  }
}
</style>
uniapps/work-wx/src/subPackages/regulationsDetail/details.vue
@@ -1,6 +1,6 @@
<template>
<view class="regulationsDetail">
    <scroll-view
    <scroll-view
        class="scroll-container"
        scroll-y
        :enable-back-to-top="true"
@@ -18,6 +18,7 @@
        </view>
    </view>
    </scroll-view>
    <u-pdf-reader v-if="pdfUrl" :src="pdfUrl"></u-pdf-reader>
</view>
</template>
<script setup>
@@ -39,10 +40,14 @@
    td: 'border: 1px solid #ddd; padding: 8rpx;'
};
const pdfUrl = ref('')
function downloadFile(item) {
    console.log(item,'999')
    // aLinkDownloadUtil(item.fileUrl, item.fileName)
    downloadAndPreview(item.fileUrl, item.fileName)
    // downloadAndPreview(item.fileUrl, item.fileName)
    pdfUrl.value = item.fileUrl
    // downloadAndSavePDF(item.fileUrl, item.fileName)
}
// 下载并打开文件(支持PDF、图片、Word等)
const downloadAndPreview = async (fileUrl, fileName) => {
@@ -50,18 +55,18 @@
        title: '下载中...',
        mask: true
    })
    try {
        // 1. 下载文件到临时目录
        const downloadRes = await uni.downloadFile({
            url: fileUrl,
            timeout: 60000
        })
        if (downloadRes.statusCode !== 200) {
            throw new Error(`下载失败: ${downloadRes.statusCode}`)
        }
        // 2. 打开文件(小程序会调用系统能力)
        uni.openDocument({
            filePath: downloadRes.tempFilePath,
@@ -80,7 +85,7 @@
                handleOpenFail(downloadRes.tempFilePath, fileName)
            }
        })
    } catch (error) {
        console.error('下载失败:', error)
        uni.showToast({
@@ -90,6 +95,84 @@
    } finally {
        uni.hideLoading()
    }
}
// 下载并保存PDF到手机(iOS需要特殊处理)
const downloadAndSavePDF = (pdfUrl, fileName = 'document.pdf') => {
  uni.showLoading({
    title: '下载中...',
    mask: true
  })
  // 检查权限(主要针对iOS)
  const checkAndDownload = () => {
    uni.downloadFile({
      url: pdfUrl,
      success: (downloadRes) => {
        uni.hideLoading()
        if (downloadRes.statusCode === 200) {
          const tempFilePath = downloadRes.tempFilePath
          // 保存到本地
          uni.saveFile({
            tempFilePath: tempFilePath,
            success: (saveRes) => {
              const savedFilePath = saveRes.savedFilePath
              uni.showModal({
                title: '下载成功',
                content: `文件已保存到: ${savedFilePath}`,
                showCancel: false,
                success: () => {
                  // 可以引导用户去文件管理查看
                }
              })
            },
            fail: (saveErr) => {
              console.error('保存失败:', saveErr)
              uni.showToast({
                title: '保存失败111',
                icon: 'error'
              })
            }
          })
        }
      },
      fail: (err) => {
        uni.hideLoading()
        uni.showToast({
          title: '下载失败1111',
          icon: 'error'
        })
      }
    })
  }
  // 检查文件访问权限
  uni.authorize({
    scope: 'scope.writePhotosAlbum',
    success: () => {
      checkAndDownload()
    },
    fail: () => {
      uni.showModal({
        title: '权限提示',
        content: '需要文件存储权限才能下载文件',
        success: (modalRes) => {
          if (modalRes.confirm) {
            uni.openSetting({
              success: (settingRes) => {
                if (settingRes.authSetting['scope.writePhotosAlbum']) {
                  checkAndDownload()
                }
              }
            })
          }
        }
      })
    }
  })
}
// 获取文件类型
@@ -142,7 +225,7 @@
    .safe-area {
        /* 处理导航栏高度 */
        padding-top: var(--status-bar-height);
        /* iOS 安全区域 */
        padding-top: constant(safe-area-inset-top);
        padding-top: env(safe-area-inset-top);
@@ -153,12 +236,12 @@
        overflow: hidden;
        /* 关键:滚动内容在安全区域内 */
        height: calc(100vh - var(--status-bar-height) - 44px);
        /* 计算高度考虑导航栏 */
        @supports (top: constant(safe-area-inset-top)) {
            height: calc(100vh - constant(safe-area-inset-top) - 44px);
        }
        @supports (top: env(safe-area-inset-top)) {
            height: calc(100vh - env(safe-area-inset-top) - 44px);
        }
@@ -166,7 +249,7 @@
    .content {
        padding: 0 24rpx 40rpx;
        .title {
            font-family: Source Han Sans CN, Source Han Sans CN;
            font-weight: 500;