吉安感知网项目-前端
张含笑
2026-01-19 eb0af63e510b5046acc7ba3bc6e1bd1cfff2954e
Merge branch 'refs/heads/master555555555555555555'
4 files modified
1 files added
630 ■■■■■ changed files
applications/task-work-order/env/.env.development 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/ApplyViewDialog.vue 514 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/FormDiaLog.vue 33 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue 71 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/supplyAddApi.js 10 ●●●●● patch | view | raw | blame | history
applications/task-work-order/env/.env.development
@@ -15,7 +15,7 @@
#开发环境代理地址(推荐本地新建文件 .env.development.local 来进行覆盖)
# VITE_APP_URL = https://wrj.shuixiongit.com/api
VITE_APP_URL= http://192.168.1.204
VITE_APP_URL= http://192.168.1.168
#新大屏地址
VITE_APP_DASHBOARD_URL = 'https://wrj.shuixiongit.com/command-center-dashboard/'
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/ApplyViewDialog.vue
New file
@@ -0,0 +1,514 @@
<template>
    <el-dialog
        class="gd-dialog"
        v-model="visible"
        :title="'查看申请'"
        @closed="visible = false"
        destroy-on-close
    >
    <div class="detail-container">
        <!-- 左侧步骤条 -->
        <div class="detail-left">
            <el-steps :active="activeStep" direction="vertical" align-center>
                <el-step v-for="(step, index) in steps" :key="index" :title="step.title">
                    <template #description>
                        <div class="step-person">{{ step.person }}</div>
                        <div class="step-time">{{ step.time }}</div>
                    </template>
                </el-step>
            </el-steps>
        </div>
        <!-- 右侧表单数据 -->
        <div class="detail-right">
        <div>
            <div class="label">需求详情</div>
            <div class="requirementsDetailsBox">
                <div class="detail-table">
                    <div class="detail-row">
                        <div class="detail-cell">
                            <span class="cell-label">需求名称</span>
                            <span class="cell-value">{{ formData.demandName }}</span>
                        </div>
                        <div class="detail-cell">
                            <span class="cell-label">需求类型</span>
                            <span class="cell-value">{{ getDictLabel(formData.demandType, dictObj.requirementType) }}</span>
                        </div>
                    </div>
                    <div class="detail-row">
                        <div class="detail-cell">
                            <span class="cell-label">需求联系人</span>
                            <span class="cell-value">{{ formData.contactPerson }}</span>
                        </div>
                        <div class="detail-cell">
                            <span class="cell-label">需求联系人电话</span>
                            <span class="cell-value">{{ formData.contactPhone }}</span>
                        </div>
                    </div>
                    <div class="detail-row">
                        <div class="detail-cell">
                            <span class="cell-label">需求邮箱</span>
                            <span class="cell-value">{{ formData.contactEmail }}</span>
                        </div>
                        <div class="detail-cell">
                            <span class="cell-label">更新周期</span>
                            <span class="cell-value">{{ formData.updateCycle }}</span>
                        </div>
                    </div>
                    <div class="detail-row">
                        <div class="detail-cell">
                            <span class="cell-label">申请依据</span>
                            <span class="cell-value">{{ formData.applyBasis }}</span>
                        </div>
                        <div class="detail-cell">
                            <span class="cell-label">共享类型</span>
                            <span class="cell-value">{{ getDictLabel(formData.shareType, dictObj.sharedType) }}</span>
                        </div>
                    </div>
                    <div class="detail-row">
                        <div class="detail-cell">
                            <span class="cell-label">应用场景类型</span>
                            <span class="cell-value">{{ getDictLabel(formData.applicationScene, dictObj.appSceneType) }}</span>
                        </div>
                        <div class="detail-cell">
                            <span class="cell-label">责任部门</span>
                            <span class="cell-value">{{ formData.responsibleDeptName }}</span>
                        </div>
                    </div>
                    <div class="detail-row">
                        <div class="detail-cell">
                            <span class="cell-label">数据来源依据</span>
                            <span class="cell-value">{{ formData.dataSource }}</span>
                        </div>
                        <div class="detail-cell">
                            <span class="cell-label">需求信息项</span>
                            <span class="cell-value">{{ formData.demandInfo }}</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
            <div>
                <div class="label">数据上传</div>
                <div class="upload-container">
                   <el-upload
                    ref="uploadRef"
                    :auto-upload="false"
                    :limit="1"
                    :on-change="handleFileChange"
                    :on-remove="handleFileRemove"
                    :before-upload="beforeFileUpload"
                    :file-list="fileList"
                    accept=".zip,.rar,.7z,.tar,.gz"
                    class="upload-demo"
                  >
                    <template #trigger>
                      <el-button type="primary">选择文件</el-button>
                    </template>
                    <template #tip>
                      <div class="el-upload__tip">
                        请上传压缩文件 (.zip/.rar/.7z/.tar/.gz)
                      </div>
                    </template>
                  </el-upload>
                  <el-button
                    type="success"
                    :disabled="!selectedFile"
                    @click="handleUpload"
                    style="margin-top: 10px;"
                  >
                    上传文件
                  </el-button>
                  <!-- 已上传文件列表 -->
                  <div v-if="uploadedFiles.length > 0" class="uploaded-files">
                    <h4>已上传文件:</h4>
                    <div v-for="(file, index) in uploadedFiles" :key="index" class="file-item">
                      <span>{{ file.originalName }}</span>
                      <el-button type="text" @click="viewFile(file)" style="margin-left: 10px;">查看</el-button>
                      <el-button type="text" @click="downloadFile(file)" style="margin-left: 5px;">下载</el-button>
                    </div>
                  </div>
                </div>
            </div>
        </div>
    </div>
        <template #footer>
            <el-button
                class="save-btn"
                color="#4C34FF"
                @click="rejectTheApplication"
            >
                拒绝申请
            </el-button>
            <el-button color="#F2F3F5"  @click="approvedByTheReview">审核通过</el-button>
        </template>
    </el-dialog>
</template>
<script setup>
import { ref, inject } from 'vue'
import { getDictLabel } from '@ztzf/utils'
import { gdSupplyDemandDetailApi, putFileAttachApi,gdSupplyDemandAuditPassApi,gdSupplyDemandAuditRejectApi } from '@/views/orderView/orderDataManage/supplyAdd/supplyAddApi'
import { ElMessage, ElMessageBox } from 'element-plus'
const dictObj = inject('dictObj')
const deptTree = inject('deptTree')
const visible = defineModel() // 弹框显隐
const formData = ref({}) // 表单数据
const uploadRef = ref() // 上传组件引用
const selectedFile = ref(null) // 选择的文件
const fileList = ref([]) // 上传文件列表
const uploadedFiles = ref([]) // 已上传文件列表
const uploadLoading = ref(false) // 上传加载状态
const responseId = ref([])
// 步骤条数据
const steps = ref([
    { title: '需求申请', person: '张三', time: '2025-03-31 12:23:30' },
    { title: '审核通过', person: '', time: '' },
])
// 当前激活步骤
const activeStep = ref(0)
// 文件选择变化
const handleFileChange = (file, fileList) => {
  if (fileList.length > 0) {
    selectedFile.value = file.raw
  } else {
    selectedFile.value = null
  }
}
// 文件移除
const handleFileRemove = () => {
  selectedFile.value = null
}
// 上传前验证
const beforeFileUpload = (file) => {
  const allowedExtensions = ['.zip', '.rar', '.7z', '.tar', '.gz']
  const fileExtension = '.' + file.name.split('.').pop().toLowerCase()
  if (!allowedExtensions.includes(fileExtension)) {
    ElMessage.error('只能上传压缩文件格式:.zip/.rar/.7z/.tar/.gz')
    return false
  }
  // 文件大小限制,这里限制为100MB
  const maxSize = 100 * 1024 * 1024 // 100MB
  if (file.size > maxSize) {
    ElMessage.error('文件大小不能超过100MB')
    return false
  }
  return true
}
// 处理文件上传
const handleUpload = async () => {
  if (!selectedFile.value) {
    ElMessage.warning('请先选择文件')
    return
  }
  // 再次验证文件类型
  if (!beforeFileUpload(selectedFile.value)) {
    return
  }
  try {
    uploadLoading.value = true
    // 创建FormData对象
    const formData = new FormData()
    formData.append('file', selectedFile.value)
    // 调用上传接口
    const response = await putFileAttachApi(formData)
    if (response.data && response.data.success) {
      const fileData = response.data.data
      // 添加到已上传文件列表
      uploadedFiles.value.push({
        name: fileData.name,
        originalName: fileData.originalName,
        link: fileData.link,
        attachId: fileData.attachId
      })
      ElMessage.success('文件上传成功!')
      // 清空上传列表
      uploadRef.value.clearFiles()
      selectedFile.value = null
      // 这里可以将附件ID保存到表单数据中,供后续提交使用
      // formData.value.attachmentId = fileData.attachId
    } else {
      ElMessage.error(response.data?.msg || '文件上传失败')
    }
  } catch (error) {
    console.error('文件上传失败:', error)
    ElMessage.error('文件上传失败,请重试')
  } finally {
    uploadLoading.value = false
  }
}
// 查看文件
const viewFile = (file) => {
  if (file.link) {
    window.open(file.link, '_blank')
  } else {
    ElMessage.warning('文件链接无效')
  }
}
// 下载文件
const downloadFile = (file) => {
  if (file.link) {
    // 创建一个隐藏的a标签来触发下载
    const a = document.createElement('a')
    a.href = file.link
    a.download = file.originalName || file.name
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
  } else {
    ElMessage.warning('文件链接无效')
  }
}
// 根据部门ID获取部门名称
function getDeptNameById(deptId, deptList) {
    // 处理类型转换,确保比较的是相同类型
    const targetId = String(deptId)
    // 递归遍历部门树
    function findDept(deptList) {
        for (const dept of deptList) {
            if (String(dept.id) === targetId) {
                return dept.name
            }
            if (Array.isArray(dept.children) && dept.children.length > 0) {
                const name = findDept(dept.children)
                if (name) return name
            }
        }
        return ''
    }
    if (!targetId || !Array.isArray(deptList) || deptList.length === 0) {
        return ''
    }
    return findDept(deptList)
}
// 打开弹框
async function open({ row }) {
    if (row?.id) {
        await loadDetail(row.id)
        // 可以在这里加载已上传的文件列表
        // loadUploadedFiles(row.id)
    }
    visible.value = true
}
// 加载详情
async function loadDetail(id) {
    const res = await gdSupplyDemandDetailApi({ id })
    const data = res?.data?.data ?? {}
    // 如果没有部门名称,根据部门ID从部门树中获取
    if (data.responsibleDeptId && !data.responsibleDeptName) {
        data.responsibleDeptName = getDeptNameById(data.responsibleDeptId, deptTree.value)
    }
    formData.value = data
}
// 如果需要加载已上传的文件列表
const loadUploadedFiles = async (id) => {
  try {
    // 这里根据实际情况调用接口获取已上传的文件列表
    // const response = await getFileListApi({ id })
    // if (response.data?.success) {
    //   uploadedFiles.value = response.data.data || []
    // }
  } catch (error) {
    console.error('加载已上传文件失败:', error)
  }
}
// 拒绝申请
const rejectTheApplication = () => {
    const id = ['2013182736046530562']
    console.log('uploadedFiles.value.attachId',uploadedFiles.value.attachId)
    gdSupplyDemandAuditRejectApi({ attachIds:id }).then(() => {
        ElMessage.success('拒绝申请成功')
        // visible.value = false
    })
}
// 审核通过
const approvedByTheReview = () => {
    const id = ['2013182736046530562']
    gdSupplyDemandAuditPassApi({ id }).then(() => {
        ElMessage.success('审核通过成功')
        visible.value = false
    })
}
defineExpose({ open })
</script>
<style scoped lang="scss">
.detail-container {
    padding: 20px;
    display: flex;
    align-items: flex-start;
    gap: 30px;
}
/* 左侧步骤条 */
.detail-left {
    width: 25%;
    padding-right: 20px;
    border-right: 1px solid #e8e8e8;
}
/* 右侧表单 */
.detail-right {
    width: 75%;
    .requirementsDetailsBox {
        background: #F2F3F5;
        border-radius: 2px 2px 2px 2px;
    }
    /* 详情表格样式 */
    .detail-table {
        width: 100%;
    }
    .detail-row {
        display: flex;
        &:last-child {
            margin-bottom: 0;
        }
    }
    .detail-cell {
        flex: 1;
        display: flex;
        justify-content: space-between;
        padding: 5px 12px;
        margin-right: 8px;
        &:last-child {
            margin-right: 0;
        }
    }
    .cell-label {
        font-weight: 500;
        color: #333333;
        margin-right: 8px;
        text-align: right;
        min-width: 100px;
        flex-shrink: 0;
    }
    .cell-value {
        color: #666666;
        flex: 1;
        text-align: left;
    }
}
/* 步骤条样式 */
:deep(.el-steps) {
    align-items: flex-start;
}
:deep(.el-step) {
    margin-bottom: 20px;
}
:deep(.el-step__title) {
    font-size: 14px;
    font-weight: 500;
    margin-bottom: 8px;
}
/* 步骤描述 */
.step-person {
    font-size: 13px;
    color: #333;
    margin-bottom: 4px;
}
.step-time {
    font-size: 12px;
    color: #909399;
}
/* 表单样式 */
.label {
    font-weight: 500;
    margin-bottom: 8px;
    color: #333;
}
/* 上传容器样式 */
.upload-container {
    padding: 15px;
    background: #F2F3F5;
    border-radius: 2px 2px 2px 2px;
}
.uploaded-files {
    margin-top: 15px;
    h4 {
        margin-bottom: 10px;
        font-size: 14px;
        color: #333333;
        font-weight: 500;
    }
    .file-item {
        display: flex;
        align-items: center;
        padding: 8px;
        background: white;
        border-radius: 4px;
        margin-bottom: 5px;
        span {
            flex: 1;
            color: #333;
        }
    }
}
.val {
    padding: 8px;
    background-color: #f5f7fa;
    border-radius: 4px;
    min-height: 32px;
    word-break: break-all;
    margin-bottom: 16px;
}
/* 上传按钮样式 */
:deep(.el-upload) {
    display: inline-block;
}
:deep(.el-upload-list) {
    margin-top: 10px;
}
</style>
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/FormDiaLog.vue
@@ -257,7 +257,31 @@
    dataSource: fieldRules(true),
    demandInfo: fieldRules(true),
}
// 根据部门ID获取部门名称
function getDeptNameById(deptId, deptList) {
    // 处理类型转换,确保比较的是相同类型
    const targetId = String(deptId)
    // 递归遍历部门树
    function findDept(deptList) {
        for (const dept of deptList) {
            if (String(dept.id) === targetId) {
                return dept.name
            }
            if (Array.isArray(dept.children) && dept.children.length > 0) {
                const name = findDept(dept.children)
                if (name) return name
            }
        }
        return ''
    }
    if (!targetId || !Array.isArray(deptList) || deptList.length === 0) {
        return ''
    }
    return findDept(deptList)
}
// 提交新增/编辑
async function handleSubmit() {
    const isValid = await formRef.value?.validate().catch(() => false)
@@ -294,7 +318,12 @@
async function loadDetail() {
    if (!formData.value.id) return
    const res = await gdSupplyDemandDetailApi({ id: formData.value.id })
    formData.value = res?.data?.data ?? {}
    const data = res?.data?.data ?? {}
    // 如果没有部门名称,根据部门ID从部门树中获取
    if (data.responsibleDeptId && !data.responsibleDeptName) {
        data.responsibleDeptName = getDeptNameById(data.responsibleDeptId, deptTree.value)
    }
    formData.value = data
}
// 打开弹框
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue
@@ -36,8 +36,8 @@
        </el-form>
        <div class="gd-table-toolbar">
            <el-button :icon="Plus" color="#4C34FF" type="primary" @click="openForm('add')">新增</el-button>
            <el-button :icon="Delete" color="#4C34FF" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
            <el-button :icon="Plus" color="#4C34FF" type="primary" @click="openForm('add')">供需填报新增</el-button>
<!--            <el-button :icon="Delete" color="#4C34FF" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>-->
        </div>
        <div class="gd-table-container" v-loading="loading">
@@ -76,8 +76,8 @@
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)">查看</el-link>
                            <el-link @click="openForm('edit', row)">编辑</el-link>
                            <el-link @click="handleDelete(row)">删除</el-link>
                            <el-link @click="openForm('edit', row)" v-if="row.demandStatus !== '1'">编辑</el-link>
                            <el-link @click="handleDelete(row)" v-if="row.demandStatus !== '1'">删除</el-link>
                        </template>
                    </el-table-column>
                </el-table>
@@ -96,16 +96,18 @@
        </div>
        <FormDiaLog ref="dialogRef" @success="getList" v-if="dialogVisible" v-model="dialogVisible" />
        <ApplyViewDialog ref="applyDialogRef" v-if="applyDialogVisible" v-model="applyDialogVisible" />
    </basic-container>
</template>
<script setup>
import { Search, RefreshRight, Plus, Delete } from '@element-plus/icons-vue'
import { onMounted, ref } from 'vue'
import { onMounted, ref, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getDictionaryByCode } from '@/api/system/dictbiz'
import { getDeptTree } from '@/api/system/dept'
import { getDictLabel } from '@ztzf/utils'
import FormDiaLog from './FormDiaLog.vue'
import ApplyViewDialog from './ApplyViewDialog.vue'
import {
    gdSupplyDemandPageApi,
    gdSupplyDemandRemoveApi,
@@ -126,10 +128,13 @@
const queryParamsRef = ref(null) // 查询表单实例
const dialogRef = ref(null) // 弹框实例
const dialogVisible = ref(false)
const applyDialogRef = ref(null) // 申请详情弹框实例
const applyDialogVisible = ref(false)
const dictObj = ref({
    requirementType: [], // 需求类型
    sharedType: [], // 共享类型
    appSceneType: [], // 应用场景类型
    demandStatus: [], // 需求状态
})
provide('dictObj', dictObj)
const deptTree = ref([]) // 部门树
@@ -140,12 +145,32 @@
provide('deptTree', deptTree)
provide('treeProps', treeProps)
// 根据部门ID获取部门名称
function getDeptNameById(deptId, deptList) {
    if (!deptId || !Array.isArray(deptList)) return ''
    for (const dept of deptList) {
        if (dept.id === deptId) {
            return dept.name
        }
        if (Array.isArray(dept.children) && dept.children.length > 0) {
            const name = getDeptNameById(deptId, dept.children)
            if (name) return name
        }
    }
    return ''
}
// 获取列表
async function getList() {
    loading.value = true
    try {
        const res = await gdSupplyDemandPageApi(searchParams.value)
        list.value = res?.data?.data?.records ?? []
        const records = res?.data?.data?.records ?? []
        // 为每条记录添加部门名称
        list.value = records.map(item => ({
            ...item,
            responsibleDeptName: item.responsibleDeptName || getDeptNameById(item.responsibleDeptId, deptTree.value)
        }))
        total.value = res?.data?.data?.total ?? 0
    } finally {
        loading.value = false
@@ -167,10 +192,26 @@
// 新增/编辑/查看 弹框
function openForm(mode, row) {
    dialogVisible.value = true
    nextTick(() => {
        dialogRef.value?.open({ mode, row })
    })
    if (mode === 'view' && row?.demandStatus === '1') {
        // 如果是查看申请中的记录,使用申请详情弹框
        openApplyViewDialog(row)
    } else {
        // 其他情况使用原有弹框
        dialogVisible.value = true
        nextTick(() => {
            dialogRef.value?.open({ mode, row })
        })
    }
}
// 打开申请详情弹框
function openApplyViewDialog(row) {
    if (row?.id) {
        applyDialogVisible.value = true
        nextTick(() => {
            applyDialogRef.value?.open({ row })
        })
    }
}
// 删除
@@ -196,22 +237,22 @@
// 获取字典
function getDictList() {
    getDictionaryByCode('requirementType,sharedType,appSceneType,demandStatus').then(res => {
    return getDictionaryByCode('requirementType,sharedType,appSceneType,demandStatus').then(res => {
        dictObj.value = res.data.data
    })
}
// 获取部门树
function getDeptTreeFun() {
    getDeptTree().then(res => {
    return getDeptTree().then(res => {
        deptTree.value = res.data.data
    })
}
onMounted(() => {
onMounted(async () => {
    // 先获取字典和部门树数据,再获取列表数据
    await Promise.all([getDictList(), getDeptTreeFun()])
    getList()
    getDictList()
    getDeptTreeFun()
})
</script>
<style scoped lang="scss"></style>
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/supplyAddApi.js
@@ -53,3 +53,13 @@
        data,
    })
}
// 文件上传
export const putFileAttachApi = (file) => {
    return request({
        url: `/blade-resource/oss/endpoint/put-file-attach`,
        method: 'post',
        data: file,
    })
}