已添加2个文件
已修改14个文件
1012 ■■■■ 文件已修改
src/views/collaborativeApproval/approvalProcess/index.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/knowledgeBase/index.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/meetSetting/index.vue 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/rpaManagement/index.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/rulesRegulationsManagement/index.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/sealManagement/index.vue 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/accounting/index.vue 231 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/payrollManagement/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/scheduling/index.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentEntry/index.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentHistory/index.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/indicatorStats/index.vue 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceRegistration/index.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentHistory/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/strategyControl/index.vue 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index.vue
@@ -25,7 +25,7 @@
      </div>
      <div>
        <el-button type="primary" @click="openForm('add')">新增</el-button>
<!--        <el-button @click="handleOut">导出</el-button>-->
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
    </div>
@@ -222,6 +222,29 @@
    tableLoading.value = false;
  })
};
// å¯¼å‡º
const handleOut = () => {
  const type = Number(props.approveType || 0)
  const urlMap = {
    0: "/approveProcess/exportZero",
    1: "/approveProcess/exportOne",
    2: "/approveProcess/exportTwo",
    3: "/approveProcess/exportThree",
    4: "/approveProcess/exportFour",
    5: "/approveProcess/exportFive",
  }
  const url = urlMap[type] || urlMap[0]
  const nameMap = {
    0: "协同审批管理表",
    1: "公出管理审批表",
    2: "请假管理审批表",
    3: "出差管理审批表",
    4: "报销管理审批表",
    5: "采购申请审批表",
  }
  const fileName = nameMap[type] || nameMap[0]
  proxy.download(url, {}, `${fileName}.xlsx`)
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection;
src/views/collaborativeApproval/knowledgeBase/index.vue
@@ -24,6 +24,7 @@
        </el-button>
      </div>
      <div>
        <el-button @click="handleExport" style="margin-right: 10px">导出</el-button>
        <el-button type="primary" @click="openForm('add')">新增知识</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
@@ -230,7 +231,7 @@
<script setup>
import { Search } from "@element-plus/icons-vue";
import { onMounted, ref, reactive, toRefs } from "vue";
import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import { listKnowledgeBase, delKnowledgeBase,addKnowledgeBase,updateKnowledgeBase } from "@/api/collaborativeApproval/knowledgeBase.js";
@@ -741,6 +742,12 @@
    // ç”¨æˆ·å–消
  });
};
// å¯¼å‡º
const { proxy } = getCurrentInstance()
const handleExport = () => {
  proxy.download('/knowledgeBase/export', { ...searchForm.value }, '知识库.xlsx')
}
</script>
<style scoped>
src/views/collaborativeApproval/notificationManagement/meetSetting/index.vue
@@ -3,10 +3,13 @@
    <!-- é¡µé¢æ ‡é¢˜ -->
    <div class="page-header">
      <h2>会议室设置</h2>
      <el-button type="primary" @click="handleAdd">
      <div>
        <el-button @click="handleExport" style="margin-right: 10px">导出</el-button>
        <el-button type="primary" @click="handleAdd">
        <el-icon><Plus /></el-icon>
        æ–°å¢žä¼šè®®å®¤
      </el-button>
        </el-button>
      </div>
    </div>
    <!-- æœç´¢åŒºåŸŸ -->
@@ -106,7 +109,7 @@
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import Pagination from '@/components/Pagination/index.vue'
@@ -271,6 +274,12 @@
  })
}
// å¯¼å‡º
const { proxy } = getCurrentInstance()
const handleExport = () => {
  proxy.download('/meeting/export', { ...searchForm }, '会议室设置.xlsx')
}
// é¡µé¢åŠ è½½æ—¶èŽ·å–æ•°æ®
onMounted(() => {
  getList()
src/views/collaborativeApproval/rpaManagement/index.vue
@@ -22,6 +22,7 @@
        </el-button>
      </div>
      <div>
        <el-button @click="handleExport" style="margin-right: 10px">导出</el-button>
        <el-button type="primary" @click="openForm('add')">新增</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
@@ -89,7 +90,7 @@
<script setup>
import { Search } from "@element-plus/icons-vue";
import { onMounted, ref, reactive, toRefs } from "vue";
import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import {listRpa, addRpa, updateRpa, delRpa, delRpaBatch} from "@/api/collaborativeApproval/rpaManagement.js";
@@ -354,6 +355,12 @@
        proxy.$modal.msg("已取消");
    });
};
// å¯¼å‡ºåŠŸèƒ½
const { proxy } = getCurrentInstance()
const handleExport = () => {
  proxy.download('/rpaProcessAutomation/export', { ...searchForm.value }, 'RPA管理.xlsx')
}
</script>
<style scoped></style>
src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
@@ -26,6 +26,7 @@
                <el-col :span="8">
                  <el-button type="primary" @click="searchRegulations">搜索</el-button>
                  <el-button @click="resetRegulationSearch">重置</el-button>
                  <el-button @click="handleExport">导出</el-button>
                  <el-button type="success" @click="handleAdd">
                    å‘布制度
                  </el-button>
@@ -227,7 +228,7 @@
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { listSealApplication, addSealApplication, updateSealApplication,listRuleManagement,addRuleManagement,updateRuleManagement,delRuleManagement,getReadingStatusByRuleId,getReadingStatusList,addReadingStatus,updateReadingStatus  } from '@/api/collaborativeApproval/sealManagement.js'
@@ -652,6 +653,12 @@
  })
}
// å¯¼å‡ºè§„章制度
const { proxy } = getCurrentInstance()
const handleExport = () => {
  proxy.download('/rulesRegulationsManagement/export', { ...regulationSearchForm }, '规章制度.xlsx')
}
// èŽ·å–å°ç« ç”³è¯·åˆ—è¡¨æ•°æ®
const getSealApplicationList = async () => {
  tableLoading.value = true
src/views/collaborativeApproval/sealManagement/index.vue
@@ -26,6 +26,7 @@
              <el-col :span="8">
                <el-button type="primary" @click="searchSealApplications">搜索</el-button>
                <el-button @click="resetSealSearch">重置</el-button>
                <el-button @click="handleExport">导出</el-button>
                <el-button type="primary" @click="showSealApplyDialog = true">申请用印
                </el-button>
              </el-col>
@@ -73,67 +74,6 @@
            </el-table>
        </div> 
    </el-card>
        <!-- è§„章制度管理 -->
          <!-- <div class="tab-content">
            <el-row :gutter="20" class="mb-20">
              <el-col :span="6">
                <el-input v-model="regulationSearchForm.title" placeholder="请输入制度标题" clearable />
              </el-col>
              <el-col :span="4">
                <el-select v-model="regulationSearchForm.category" placeholder="制度分类" clearable>
                  <el-option label="人事制度" value="hr" />
                  <el-option label="财务制度" value="finance" />
                  <el-option label="安全制度" value="safety" />
                  <el-option label="技术制度" value="tech" />
                </el-select>
              </el-col>
              <el-col :span="8">
                <el-button type="primary" @click="searchRegulations">搜索</el-button>
                <el-button @click="resetRegulationSearch">重置</el-button>
                <el-button type="success" @click="handleAdd">
                  å‘布制度
                </el-button>
              </el-col>
            </el-row>
            <el-table :data="regulations" border v-loading="tableLoading"  style="width: 100%">
              <el-table-column prop="regulationNum" label="制度编号" width="120" />
              <el-table-column prop="title" label="制度标题" min-width="200" />
              <el-table-column prop="category" label="分类" width="120">
                <template #default="scope">
                  <el-tag>{{ getCategoryText(scope.row.category) }}</el-tag>
                </template>
              </el-table-column>
              <el-table-column prop="version" label="版本" width="80" />
              <el-table-column prop="createUserName" label="发布人" width="120" />
              <el-table-column prop="createTime" label="发布时间" width="180" />
              <el-table-column prop="status" label="状态" width="100">
                <template #default="scope">
                  <el-tag :type="scope.row.status === 'active' ? 'success' : 'info'">
                    {{ scope.row.status === 'active' ? '生效中' : '已废止' }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column prop="readCount" label="已读人数" width="100" />
              <el-table-column label="操作" width="250" fixed="right">
                <template #default="scope">
                  <el-button link @click="viewRegulation(scope.row)">查看</el-button>
                  <el-button link type="primary" @click="handleEdit(scope.row)">编辑</el-button>
                  <el-button link type="danger" @click="repealEdit(scope.row)">废弃</el-button>
                  <el-button link type="success" @click="viewVersionHistory(scope.row)">版本历史</el-button>
                  <el-button link type="warning" @click="viewReadStatus(scope.row)">阅读状态</el-button>
                </template>
              </el-table-column>
            </el-table>
          </div> -->
    <!-- ç”¨å°ç”³è¯·å¯¹è¯æ¡† -->
    <el-dialog v-model="showSealApplyDialog" title="申请用印" width="600px">
@@ -298,7 +238,7 @@
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, onMounted, getCurrentInstance } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { listSealApplication, addSealApplication, updateSealApplication,listRuleManagement,addRuleManagement,updateRuleManagement,delRuleManagement,getReadingStatusByRuleId,getReadingStatusList,addReadingStatus,updateReadingStatus  } from '@/api/collaborativeApproval/sealManagement.js'
@@ -723,6 +663,12 @@
  })
}
// å¯¼å‡ºç”¨å°ç”³è¯·
const { proxy } = getCurrentInstance()
const handleExport = () => {
  proxy.download('/sealApplicationManagement/export', { ...sealSearchForm }, '用印申请.xlsx')
}
// èŽ·å–å°ç« ç”³è¯·åˆ—è¡¨æ•°æ®
const getSealApplicationList = async () => {
  tableLoading.value = true
src/views/financialManagement/accounting/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,231 @@
<template>
  <div class="app-container">
    <el-row :gutter="16" class="mb-16">
      <el-col :span="12">
        <el-card shadow="hover">
          <div class="section-title">统一会计科目体系</div>
          <el-tree
            :data="accountTree"
            node-key="code"
            :props="{ label: 'label', children: 'children' }"
            highlight-current
            default-expand-all
          />
        </el-card>
      </el-col>
      <el-col :span="12">
        <el-card shadow="hover">
          <div class="section-title">凭证模板</div>
          <el-table :data="voucherTemplates" border size="small">
            <el-table-column prop="name" label="模板名称" min-width="140" />
            <el-table-column prop="bizScene" label="业务场景" min-width="140" />
            <el-table-column prop="debit" label="借方科目" min-width="160" />
            <el-table-column prop="credit" label="贷方科目" min-width="160" />
            <el-table-column prop="auxDims" label="辅助核算维度" min-width="180">
              <template #default="scope">
                <el-space wrap>
                  <el-tag v-for="dim in scope.row.auxDims" :key="dim" size="small" type="info">{{ dim }}</el-tag>
                </el-space>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
      </el-col>
    </el-row>
    <el-row :gutter="16" class="mb-16">
      <el-col :span="12">
        <el-card shadow="hover">
          <div class="section-title">业务流程 â†’ å‡­è¯è‡ªåŠ¨ç”Ÿæˆ</div>
          <div class="toolbar">
            <el-text type="info">演示数据仅用于展示结构与字段</el-text>
          </div>
          <el-table :data="generatedVouchers" border size="small">
            <el-table-column prop="date" label="日期" width="110" />
            <el-table-column prop="bizScene" label="业务场景" min-width="120" />
            <el-table-column prop="summary" label="摘要" min-width="160" />
            <el-table-column prop="amount" label="金额(Â¥)" width="110" />
            <el-table-column prop="status" label="状态" width="100">
              <template #default="scope">
                <el-tag :type="scope.row.status === '已生成' ? 'success' : 'warning'">{{ scope.row.status }}</el-tag>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
      </el-col>
      <el-col :span="12">
        <el-card shadow="hover">
          <div class="section-title">多维辅助核算</div>
          <div class="dims">
            <el-tag type="success">客户</el-tag>
            <el-tag type="warning">项目</el-tag>
            <el-tag type="info">部门</el-tag>
            <el-tag type="primary">管理员</el-tag>
          </div>
          <el-table :data="auxSummary" size="small" border>
            <el-table-column prop="dimension" label="维度" width="100" />
            <el-table-column prop="category" label="类别" min-width="140" />
            <el-table-column prop="debit" label="借方(本期)" width="110" />
            <el-table-column prop="credit" label="贷方(本期)" width="110" />
            <el-table-column prop="balance" label="余额" width="100" />
          </el-table>
        </el-card>
      </el-col>
    </el-row>
    <el-row :gutter="16" class="mb-16">
      <el-col :span="12">
        <el-card shadow="hover">
          <div class="section-title">结账任务(月/å­£/年)</div>
          <div class="toolbar">
            <el-space>
              <el-button size="small" @click="runClose('月结')">执行月结</el-button>
              <el-button size="small" @click="runClose('季报')">执行季报</el-button>
              <el-button size="small" @click="runClose('年度结账')">执行年度结账</el-button>
            </el-space>
          </div>
          <el-timeline style="margin-top: 6px;">
            <el-timeline-item
              v-for="item in closingTasks"
              :key="item.id"
              :type="item.type"
              :timestamp="item.time"
              placement="top"
            >
              <div class="close-item">
                <div class="title">{{ item.name }}</div>
                <el-tag :type="item.status === '完成' ? 'success' : 'info'" size="small">{{ item.status }}</el-tag>
              </div>
            </el-timeline-item>
          </el-timeline>
        </el-card>
      </el-col>
      <el-col :span="12">
        <el-card shadow="hover">
          <div class="section-title">审计留痕与审批权限</div>
          <el-table :data="auditTrail" border size="small">
            <el-table-column prop="time" label="时间" width="160" />
            <el-table-column prop="action" label="动作" min-width="160" />
            <el-table-column prop="bizScene" label="关联业务" min-width="140" />
            <el-table-column prop="role" label="执行角色" width="120" />
            <el-table-column prop="result" label="结果" width="100">
              <template #default="scope">
                <el-tag :type="scope.row.result === '通过' ? 'success' : (scope.row.result === '驳回' ? 'danger' : 'info')">
                  {{ scope.row.result }}
                </el-tag>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>
<script setup>
import { ref } from 'vue'
// ç§‘目树(示例)
const accountTree = ref([
  { code: '1001', label: '资产', children: [
    { code: '100101', label: '库存现金' },
    { code: '100102', label: '银行存款' },
    { code: '1122', label: '应收账款' },
    { code: '1601', label: '固定资产' },
  ]},
  { code: '2001', label: '负债', children: [
    { code: '2202', label: '应付账款' },
    { code: '2241', label: '其他应付款' },
  ]},
  { code: '3001', label: '所有者权益', children: [
    { code: '3103', label: '本年利润' },
  ]},
  { code: '4001', label: '成本费用', children: [
    { code: '5601', label: '制造费用' },
    { code: '6602', label: '管理费用' },
  ]},
])
// å‡­è¯æ¨¡æ¿ï¼ˆç¤ºä¾‹ï¼‰
const voucherTemplates = ref([
  { name: '销售收入确认', bizScene: '销售出库', debit: '1122 åº”收账款', credit: '6001 ä¸»è¥ä¸šåŠ¡æ”¶å…¥', auxDims: ['客户','项目'] },
  { name: '采购应付确认', bizScene: '采购入库', debit: '1403 åœ¨é€”物资', credit: '2202 åº”付账款', auxDims: ['项目','部门'] },
  { name: '费用报销', bizScene: '费用单', debit: '6602 ç®¡ç†è´¹ç”¨', credit: '1002 é“¶è¡Œå­˜æ¬¾', auxDims: ['部门'] },
  { name: '固定资产折旧', bizScene: '月末折旧', debit: '6602 ç®¡ç†è´¹ç”¨', credit: '1602 ç´¯è®¡æŠ˜æ—§', auxDims: ['部门'] },
])
// è‡ªåŠ¨ç”Ÿæˆçš„å‡­è¯ï¼ˆç¤ºä¾‹ï¼‰
const generatedVouchers = ref([
  { date: '2025-10-01', bizScene: '销售出库', summary: '确认应收与收入', amount: 128000, status: '已生成' },
  { date: '2025-10-03', bizScene: '采购入库', summary: '确认到货应付', amount: 56000, status: '已生成' },
  { date: '2025-10-05', bizScene: '费用单', summary: '办公费用报销', amount: 3200, status: '已生成' },
])
// æ— æ¨¡æ‹Ÿç”Ÿæˆæ“ä½œï¼Œä»…展示静态示例数据
// è¾…助核算示例汇总(无个人姓名,仅维度类别)
const auxSummary = ref([
  { dimension: '客户', category: '重点客户集合', debit: 320000, credit: 210000, balance: 110000 },
  { dimension: '项目', category: '项目A', debit: 150000, credit: 120000, balance: 30000 },
  { dimension: '部门', category: '运营中心', debit: 42000, credit: 18000, balance: 24000 },
  { dimension: '管理员', category: '系统角色', debit: 0, credit: 0, balance: 0 },
])
// ç»“账任务
const closingTasks = ref([
  { id: 1, name: '2025å¹´10月 æœˆç»“', time: '2025-10-31 18:00', status: '完成', type: 'success' },
  { id: 2, name: '2025å¹´Q4 å­£æŠ¥', time: '2025-12-31 18:00', status: '计划', type: 'info' },
  { id: 3, name: '2025年度 å¹´åº¦ç»“è´¦', time: '2025-12-31 23:00', status: '计划', type: 'info' },
])
function runClose(kind) {
  closingTasks.value.unshift({
    id: Date.now(),
    name: `${new Date().getFullYear()}å¹´${kind}`,
    time: new Date().toISOString().replace('T',' ').slice(0,16),
    status: '完成',
    type: 'success',
  })
}
// å®¡è®¡ç•™ç—•(不含个人姓名,仅角色/机制)
const auditTrail = ref([
  { time: '2025-10-01 09:12', action: '销售出库触发凭证生成', bizScene: '销售出库', role: '系统自动化', result: '通过' },
  { time: '2025-10-03 14:20', action: '采购入库触发应付确认', bizScene: '采购入库', role: '系统自动化', result: '通过' },
  { time: '2025-10-05 10:03', action: '费用单审批', bizScene: '费用单', role: '财务审批', result: '通过' },
  { time: '2025-10-08 16:45', action: '凭证过账', bizScene: '总账', role: '会计审核', result: '通过' },
  { time: '2025-10-31 18:05', action: '月结完成并锁账', bizScene: '总账', role: '系统自动化', result: '通过' },
])
</script>
<style scoped lang="scss">
.app-container {
  padding: 16px;
}
.page-header {
  margin-bottom: 12px;
  h2 { margin: 0 0 6px 0; font-weight: 600; }
  p { margin: 0; color: #666; }
}
.section-title {
  position: relative;
  padding-left: 10px;
  margin-bottom: 10px;
  font-weight: 700;
}
.section-title::before {
  content: '';
  position: absolute;
  left: 0; top: 0.2em;
  width: 4px; height: 1.2em;
  background: #002FA7;
  border-radius: 2px;
}
.mb-16 { margin-bottom: 16px; }
.toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.dims { display: flex; gap: 8px; margin-bottom: 10px; }
.close-item { display: flex; align-items: center; gap: 8px; }
</style>
src/views/personnelManagement/payrollManagement/index.vue
@@ -27,8 +27,8 @@
                >
            </div>
            <div>
                <el-button @click="handleExport" style="margin-right: 10px">导出</el-button>
                <el-button type="primary" @click="openForm('add')">新增薪资</el-button>
<!--                <el-button @click="handleOut">导出</el-button>-->
                <el-button type="danger" plain @click="handleDelete">删除</el-button>
            </div>
        </div>
@@ -51,7 +51,7 @@
<script setup>
import { Search } from "@element-plus/icons-vue";
import {onMounted, ref} from "vue";
import {onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick} from "vue";
import FormDia from "@/views/personnelManagement/payrollManagement/components/formDia.vue";
import {staffJoinDel} from "@/api/personnelManagement/onboarding.js";
import {ElMessageBox} from "element-plus";
@@ -283,6 +283,22 @@
            proxy.$modal.msg("已取消");
        });
};
// å¯¼å‡ºè–ªèµ„管理
const handleExport = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/compensationPerformance/export", { ...searchForm.value, ...page }, "薪资管理.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
onMounted(() => {
    getList();
});
src/views/personnelManagement/scheduling/index.vue
@@ -37,6 +37,10 @@
            <el-icon><Refresh/></el-icon>
            é‡ç½®
          </el-button>
          <el-button @click="handleExport">
            <el-icon><Download/></el-icon>
            å¯¼å‡º
          </el-button>
          <el-button type="primary" @click="openScheduleDialog('add')">
          <el-icon><Plus/></el-icon>
          æ–°å¢žæŽ’班
@@ -244,7 +248,7 @@
</template>
<script setup>
import {ref, reactive, computed, onMounted} from 'vue'
import {ref, reactive, computed, onMounted, getCurrentInstance} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import {useDict} from "@/utils/dict.js"
import {Plus, Download, Search, Refresh} from '@element-plus/icons-vue'
@@ -252,6 +256,8 @@
import {getStaffOnJob} from "@/api/personnelManagement/onboarding.js";
import dayjs from "dayjs";
import pagination from "@/components/PIMTable/Pagination.vue";
const { proxy } = getCurrentInstance();
const tableCount = ref(0)
// å“åº”式数据
@@ -482,6 +488,17 @@
  selectedRows.value = selection
}
// å¯¼å‡º
const handleExport = () => {
  let searchForm = {
    ...filterForm,
    ...(filterForm.dateRange.length > 0 && {
      startDate: filterForm.dateRange[0],
      endDate: filterForm.dateRange[1],
    })
  }
  proxy.download('/staff/staffScheduling/export', {}, '人员排班.xlsx')
}
// ç”Ÿå‘½å‘¨æœŸ
onMounted(() => {
src/views/procurementManagement/invoiceEntry/index.vue
@@ -45,10 +45,10 @@
      <div class="actions">
        <div></div>
        <div>
          <el-button @click="handleExport" style="margin-right: 10px">导出</el-button>
          <el-button type="primary" @click="handleAdd('add')">
            æ–°å¢žç™»è®°
          </el-button>
<!--          <el-button @click="handleOut">导出</el-button>-->
<!--          <el-button type="danger" plain @click="handleDelete">删除</el-button>-->
        </div>
      </div>
@@ -92,7 +92,7 @@
<script setup>
import { usePaginationApi } from "@/hooks/usePaginationApi";
import {delRegistration, gePurchaseListPage} from "@/api/procurementManagement/invoiceEntry.js";
import { nextTick, onMounted, getCurrentInstance } from "vue";
import { nextTick, onMounted, getCurrentInstance, ref } from "vue";
import ExpandTable from "./components/ExpandTable.vue";
import Modal from "./components/Modal.vue";
import {ElMessageBox} from "element-plus";
@@ -223,6 +223,22 @@
            proxy.$modal.msg("已取消");
        });
};
// å¯¼å‡ºé‡‡è´­å°è´¦
const handleExport = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/purchase/ledger/exportOne", {}, "来票登记.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
};
// åˆ é™¤
const handleDelete = () => {
    let ids = [];
src/views/procurementManagement/paymentEntry/index.vue
@@ -27,6 +27,7 @@
          </el-col>
          <el-col :span="4">
            <el-form-item style="float: right; margin-right: unset">
              <el-button @click="handleExport" style="margin-right: 10px">导出</el-button>
              <el-button type="primary" @click="openForm('add')">
                æ–°å¢žä»˜æ¬¾
              </el-button>
@@ -269,7 +270,7 @@
</template>
<script setup>
import { ref } from "vue";
import { ref, reactive, toRefs, getCurrentInstance, nextTick, onMounted } from "vue";
import { Search } from "@element-plus/icons-vue";
import { ElMessageBox } from "element-plus";
import useUserStore from "@/store/modules/user.js";
@@ -567,7 +568,25 @@
  const day = String(today.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
getList();
// å¯¼å‡º
const handleExport = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download("/purchase/registration/exportOne", { ...searchForm, ...page }, "付款登记.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
onMounted(() => {
  getList();
});
</script>
<style scoped lang="scss">
src/views/procurementManagement/paymentHistory/index.vue
@@ -32,6 +32,7 @@
        >
          æœç´¢
        </el-button>
        <el-button @click="handleExport">导出</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
@@ -53,7 +54,7 @@
</template>
<script setup>
import { ref } from "vue";
import { ref, reactive, getCurrentInstance, onMounted } from "vue";
import { Search } from "@element-plus/icons-vue";
import { paymentHistoryListPage } from "@/api/procurementManagement/paymentEntry.js";
import useFormData from "@/hooks/useFormData";
@@ -106,12 +107,9 @@
const total = ref(0);
const { form: searchForm } = useFormData({
  searchText: undefined,
  paymentDate: [
    dayjs().startOf("month").format("YYYY-MM-DD"),
    dayjs().endOf("month").format("YYYY-MM-DD"),
  ],
  paymentDateStart: dayjs().startOf("month").format("YYYY-MM-DD"),
  paymentDateEnd: dayjs().endOf("month").format("YYYY-MM-DD"),
  paymentDate: [],
  paymentDateStart: undefined,
  paymentDateEnd: undefined,
});
// æŸ¥è¯¢åˆ—表
@@ -161,6 +159,12 @@
  getList();
};
// å¯¼å‡º
const handleExport = () => {
  const { paymentDate, ...rest } = searchForm;
  proxy.download("/purchase/paymentRegistration/export", { ...rest, ...page }, "付款流水.xlsx");
};
onMounted(() => {
  getList();
});
src/views/salesManagement/indicatorStats/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,246 @@
<template>
  <div class="app-container indicator-stats">
    <el-card class="box-card">
      <!-- KPI æ±‡æ€» -->
      <el-row :gutter="20" class="stats-row">
        <el-col :span="6">
          <div class="stat-card">
            <div class="stat-icon" style="background: #ecf5ff;">
              <el-icon :size="30" color="#409eff"><Document /></el-icon>
            </div>
            <div class="stat-content">
              <div class="stat-value">{{ indicatorKpis.orderCount.toLocaleString() }}</div>
              <div class="stat-label">订单数量</div>
            </div>
          </div>
        </el-col>
        <el-col :span="6">
          <div class="stat-card">
            <div class="stat-icon" style="background: #f0f9ff;">
              <el-icon :size="30" color="#67c23a"><Tickets /></el-icon>
            </div>
            <div class="stat-content">
              <div class="stat-value">Â¥{{ indicatorKpis.salesAmount.toLocaleString() }}</div>
              <div class="stat-label">销售额</div>
            </div>
          </div>
        </el-col>
        <el-col :span="6">
          <div class="stat-card">
            <div class="stat-icon" style="background: #fef0f0;">
              <el-icon :size="30" color="#e6a23c"><Van /></el-icon>
            </div>
            <div class="stat-content">
              <div class="stat-value">{{ indicatorKpis.shipmentRate }}%</div>
              <div class="stat-label">发货率</div>
            </div>
          </div>
        </el-col>
        <el-col :span="6">
          <div class="stat-card">
            <div class="stat-icon" style="background: #f4f4f5;">
              <el-icon :size="30" color="#f56c6c"><Wallet /></el-icon>
            </div>
            <div class="stat-content">
              <div class="stat-value">{{ indicatorKpis.collectionRate }}%</div>
              <div class="stat-label">回款率</div>
            </div>
          </div>
        </el-col>
      </el-row>
      <!-- ç»´åº¦ç­›é€‰ -->
      <el-row :gutter="20" class="search-row">
        <el-col :span="6">
          <el-select v-model="indicatorFilter.product" placeholder="产品" clearable>
            <el-option label="全部产品" value="" />
            <el-option label="P.O 42.5普通硅酸盐水泥" value="P.O 42.5普通硅酸盐水泥" />
            <el-option label="P.S 32.5矿渣硅酸盐水泥" value="P.S 32.5矿渣硅酸盐水泥" />
            <el-option label="P.C 32.5复合硅酸盐水泥" value="P.C 32.5复合硅酸盐水泥" />
          </el-select>
        </el-col>
        <el-col :span="6">
          <el-select v-model="indicatorFilter.customer" placeholder="客户" clearable>
            <el-option label="全部客户" value="" />
            <el-option label="华东建材集团" value="华东建材集团" />
            <el-option label="长江混凝土公司" value="长江混凝土公司" />
            <el-option label="浦江水泥制品厂" value="浦江水泥制品厂" />
          </el-select>
        </el-col>
        <el-col :span="6">
          <el-select v-model="indicatorFilter.region" placeholder="区域" clearable>
            <el-option label="全部区域" value="" />
            <el-option label="华东地区" value="华东地区" />
            <el-option label="华南地区" value="华南地区" />
            <el-option label="华北地区" value="华北地区" />
          </el-select>
        </el-col>
        <el-col :span="6">
          <el-date-picker v-model="indicatorFilter.dateRange" type="daterange" range-separator="至"
                          start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" style="width: 100%" />
        </el-col>
        <el-col :span="24" style="text-align: right; margin-top: 10px;">
          <el-button type="primary" @click="applyIndicatorFilter">查询</el-button>
          <el-button @click="resetIndicatorFilter">重置</el-button>
          <el-button @click="exportIndicatorTable">导出报表</el-button>
          <el-button @click="exportIndicatorChart">导出图表</el-button>
        </el-col>
      </el-row>
      <!-- å›¾è¡¨åŒº -->
      <div class="chart-container">
        <div ref="indicatorChartRef" style="width: 100%; height: 360px;"></div>
      </div>
      <!-- ä¸šç»©ç»Ÿè®¡ï¼ˆå›¢é˜Ÿç»´åº¦ï¼Œæ— ä¸ªäººå§“名) -->
      <el-table :data="teamPerformanceList" border stripe style="margin-top: 20px;">
        <el-table-column prop="team" label="销售团队"/>
        <el-table-column prop="orderCount" label="订单数"/>
        <el-table-column prop="salesAmount" label="销售额">
          <template #default="scope">Â¥{{ scope.row.salesAmount.toLocaleString() }}</template>
        </el-table-column>
        <el-table-column prop="shipmentRate" label="发货率">
          <template #default="scope">{{ scope.row.shipmentRate }}%</template>
        </el-table-column>
        <el-table-column prop="collectionRate" label="回款率">
          <template #default="scope">{{ scope.row.collectionRate }}%</template>
        </el-table-column>
        <el-table-column prop="attainment" label="目标达成率">
          <template #default="scope">
            <el-tag :type="scope.row.attainment >= 100 ? 'success' : scope.row.attainment >= 80 ? 'warning' : 'danger'">
              {{ scope.row.attainment }}%
            </el-tag>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick } from 'vue'
import { Document, Van, Tickets, Wallet } from '@element-plus/icons-vue'
import * as echarts from 'echarts'
const indicatorKpis = reactive({
  orderCount: 1280,
  salesAmount: 9650000,
  shipmentRate: 89.2,
  collectionRate: 76.4
})
const indicatorFilter = reactive({
  product: '',
  customer: '',
  region: '',
  dateRange: []
})
const indicatorChartRef = ref(null)
let indicatorChart = null
const teamPerformanceList = ref([
  { team: '华东大区', orderCount: 320, salesAmount: 2850000, shipmentRate: 90, collectionRate: 80, attainment: 105 },
  { team: '华北大区', orderCount: 280, salesAmount: 2150000, shipmentRate: 86, collectionRate: 73, attainment: 92 },
  { team: '华南大区', orderCount: 210, salesAmount: 1850000, shipmentRate: 88, collectionRate: 70, attainment: 78 },
  { team: '西南大区', orderCount: 180, salesAmount: 1500000, shipmentRate: 83, collectionRate: 68, attainment: 74 }
])
const initIndicatorChart = () => {
  if (!indicatorChartRef.value) return
  if (indicatorChart) indicatorChart.dispose()
  indicatorChart = echarts.init(indicatorChartRef.value)
  const option = {
    title: { text: '多维度销售指标趋势', left: 'center' },
    tooltip: { trigger: 'axis' },
    legend: { data: ['订单数', '销售额', '发货率', '回款率'], top: 30 },
    grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
    xAxis: { type: 'category', data: ['2024-12', '2025-01', '2025-02', '2025-03', '2025-04', '2025-05'] },
    yAxis: [
      { type: 'value', name: '数量/金额', axisLabel: { formatter: '{value}' } },
      { type: 'value', name: '比例(%)', min: 0, max: 100, axisLabel: { formatter: '{value}%' } }
    ],
    series: [
      { name: '订单数', type: 'bar', data: [180, 220, 210, 260, 205, 225], itemStyle: { color: '#409eff' } },
      { name: '销售额', type: 'bar', data: [820, 950, 910, 1080, 980, 1020], itemStyle: { color: '#67c23a' } },
      { name: '发货率', type: 'line', yAxisIndex: 1, data: [86, 89, 88, 91, 87, 90], itemStyle: { color: '#e6a23c' } },
      { name: '回款率', type: 'line', yAxisIndex: 1, data: [72, 76, 74, 79, 75, 78], itemStyle: { color: '#f56c6c' } }
    ]
  }
  indicatorChart.setOption(option)
}
const applyIndicatorFilter = () => {
  const random = (base, delta) => {
    const v = base + Math.round((Math.random() - 0.5) * delta)
    return v < 0 ? 0 : v
  }
  indicatorKpis.orderCount = random(1280, 120)
  indicatorKpis.salesAmount = random(9650000, 350000)
  indicatorKpis.shipmentRate = (85 + Math.random() * 10).toFixed(1) * 1
  indicatorKpis.collectionRate = (70 + Math.random() * 12).toFixed(1) * 1
  setTimeout(() => initIndicatorChart(), 200)
}
const resetIndicatorFilter = () => {
  indicatorFilter.product = ''
  indicatorFilter.customer = ''
  indicatorFilter.region = ''
  indicatorFilter.dateRange = []
  applyIndicatorFilter()
}
const exportIndicatorTable = () => {
  const header = ['销售团队', '订单数', '销售额', '发货率(%)', '回款率(%)', '目标达成率(%)']
  const rows = teamPerformanceList.value.map(r => [
    r.team,
    r.orderCount,
    r.salesAmount,
    r.shipmentRate,
    r.collectionRate,
    r.attainment
  ])
  const csv = [header, ...rows].map(r => r.join(',')).join('\n')
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
  const url = URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = '指标统计-团队业绩.csv'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
  URL.revokeObjectURL(url)
}
const exportIndicatorChart = () => {
  if (!indicatorChart) return
  const url = indicatorChart.getDataURL({ type: 'png', pixelRatio: 2, backgroundColor: '#fff' })
  const link = document.createElement('a')
  link.href = url
  link.download = '指标统计-图表.png'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}
onMounted(() => {
  nextTick(() => initIndicatorChart())
})
</script>
<style scoped>
.indicator-stats {
  padding: 0;
}
.box-card { border: none; box-shadow: none; }
.search-row { margin-bottom: 20px; }
.stats-row { margin-bottom: 24px; }
.stat-card { display: flex; align-items: center; padding: 20px; background: #fff; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); }
.stat-icon { width: 60px; height: 60px; display: flex; align-items: center; justify-content: center; border-radius: 8px; margin-right: 16px; }
.stat-content { flex: 1; }
.stat-value { font-size: 28px; font-weight: bold; color: #303133; margin-bottom: 4px; }
.stat-label { font-size: 14px; color: #909399; }
.chart-container { margin: 20px 0; padding: 20px; background: #fff; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); }
</style>
src/views/salesManagement/invoiceRegistration/index.vue
@@ -36,15 +36,18 @@
        <el-form-item>
          <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
          <el-button @click="resetForm"> é‡ç½® </el-button>
          <el-button @click="handleExport" style="margin-right: 10px">导出</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="table_list">
      <div class="flex justify-between">
        <div></div>
        <div>
        <el-button type="primary" @click="openForm" style="margin-bottom: 8px">
          æ–°å¢žç™»è®°
        </el-button>
        </div>
      </div>
      <el-table
        :data="tableData"
@@ -599,6 +602,21 @@
    });
};
// å¯¼å‡ºé”€å”®å°è´¦
const handleExport = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      proxy.download("/sales/ledger/exportOne", { ...searchForm, ...page }, "开票登记.xlsx");
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
//本次开票失焦操作
const invoiceNumBlur = (row) => {
  if (!row.currentInvoiceNum) {
src/views/salesManagement/receiptPaymentHistory/index.vue
@@ -44,6 +44,7 @@
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleQuery"> æœç´¢ </el-button>
        <el-button @click="handleExport">导出</el-button>
      </el-form-item>
    </el-form>
    <div class="table_list">
@@ -65,7 +66,7 @@
</template>
<script setup>
import { ref } from "vue";
import { ref, reactive, getCurrentInstance } from "vue";
import { Search } from "@element-plus/icons-vue";
import { receiptPaymentHistoryListPage } from "@/api/salesManagement/receiptPayment.js";
import useFormData from "@/hooks/useFormData";
@@ -145,14 +146,9 @@
const { form: searchForm } = useFormData({
  searchText: undefined,
  receiptPaymentDate: [
    dayjs().startOf("month").format("YYYY-MM-DD"),
    dayjs().endOf("month").format("YYYY-MM-DD"),
  ],
  receiptPaymentDateStart: dayjs()
    .startOf("month")
    .format("YYYY-MM-DD 00:00:00"),
  receiptPaymentDateEnd: dayjs().endOf("month").format("YYYY-MM-DD 23:59:59"),
  receiptPaymentDate: [],
  receiptPaymentDateStart: undefined,
  receiptPaymentDateEnd: undefined,
  customerContractNo: undefined,
  projectName: undefined,
});
@@ -209,6 +205,12 @@
  getList();
};
// å¯¼å‡º
const handleExport = () => {
  const { receiptPaymentDate, ...rest } = searchForm;
  proxy.download("/receiptPayment/exportOne", { ...rest, ...page }, "回款流水.xlsx");
};
onMounted(() => {
  getList();
});
src/views/salesManagement/strategyControl/index.vue
@@ -474,6 +474,124 @@
          />
        </el-card>
      </el-tab-pane>
      <!-- æŒ‡æ ‡ç»Ÿè®¡ï¼ˆå¤šç»´åº¦é”€å”®åˆ†æžï¼‰ -->
      <el-tab-pane label="指标统计" name="indicatorStats">
        <el-card class="box-card">
          <!-- KPI æ±‡æ€» -->
          <el-row :gutter="20" class="stats-row">
            <el-col :span="6">
              <div class="stat-card">
                <div class="stat-icon" style="background: #ecf5ff;">
                  <el-icon :size="30" color="#409eff"><Document /></el-icon>
                </div>
                <div class="stat-content">
                  <div class="stat-value">{{ indicatorKpis.orderCount.toLocaleString() }}</div>
                  <div class="stat-label">订单数量</div>
                </div>
              </div>
            </el-col>
            <el-col :span="6">
              <div class="stat-card">
                <div class="stat-icon" style="background: #f0f9ff;">
                  <el-icon :size="30" color="#67c23a"><Tickets /></el-icon>
                </div>
                <div class="stat-content">
                  <div class="stat-value">Â¥{{ indicatorKpis.salesAmount.toLocaleString() }}</div>
                  <div class="stat-label">销售额</div>
                </div>
              </div>
            </el-col>
            <el-col :span="6">
              <div class="stat-card">
                <div class="stat-icon" style="background: #fef0f0;">
                  <el-icon :size="30" color="#e6a23c"><Van /></el-icon>
                </div>
                <div class="stat-content">
                  <div class="stat-value">{{ indicatorKpis.shipmentRate }}%</div>
                  <div class="stat-label">发货率</div>
                </div>
              </div>
            </el-col>
            <el-col :span="6">
              <div class="stat-card">
                <div class="stat-icon" style="background: #f4f4f5;">
                  <el-icon :size="30" color="#f56c6c"><Wallet /></el-icon>
                </div>
                <div class="stat-content">
                  <div class="stat-value">{{ indicatorKpis.collectionRate }}%</div>
                  <div class="stat-label">回款率</div>
                </div>
              </div>
            </el-col>
          </el-row>
          <!-- ç»´åº¦ç­›é€‰ -->
          <el-row :gutter="20" class="search-row">
            <el-col :span="6">
              <el-select v-model="indicatorFilter.product" placeholder="产品" clearable>
                <el-option label="全部产品" value="" />
                <el-option label="P.O 42.5普通硅酸盐水泥" value="P.O 42.5普通硅酸盐水泥" />
                <el-option label="P.S 32.5矿渣硅酸盐水泥" value="P.S 32.5矿渣硅酸盐水泥" />
                <el-option label="P.C 32.5复合硅酸盐水泥" value="P.C 32.5复合硅酸盐水泥" />
              </el-select>
            </el-col>
            <el-col :span="6">
              <el-select v-model="indicatorFilter.customer" placeholder="客户" clearable>
                <el-option label="全部客户" value="" />
                <el-option label="华东建材集团" value="华东建材集团" />
                <el-option label="长江混凝土公司" value="长江混凝土公司" />
                <el-option label="浦江水泥制品厂" value="浦江水泥制品厂" />
              </el-select>
            </el-col>
            <el-col :span="6">
              <el-select v-model="indicatorFilter.region" placeholder="区域" clearable>
                <el-option label="全部区域" value="" />
                <el-option label="华东地区" value="华东地区" />
                <el-option label="华南地区" value="华南地区" />
                <el-option label="华北地区" value="华北地区" />
              </el-select>
            </el-col>
            <el-col :span="6">
              <el-date-picker v-model="indicatorFilter.dateRange" type="daterange" range-separator="至"
                              start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" style="width: 100%" />
            </el-col>
            <el-col :span="24" style="text-align: right; margin-top: 10px;">
              <el-button type="primary" @click="applyIndicatorFilter">查询</el-button>
              <el-button @click="resetIndicatorFilter">重置</el-button>
              <el-button @click="exportIndicatorTable">导出报表</el-button>
              <el-button @click="exportIndicatorChart">导出图表</el-button>
            </el-col>
          </el-row>
          <!-- å›¾è¡¨åŒº -->
          <div class="chart-container">
            <div ref="indicatorChartRef" style="width: 100%; height: 360px;"></div>
          </div>
          <!-- ä¸šç»©ç»Ÿè®¡ï¼ˆå›¢é˜Ÿç»´åº¦ï¼Œæ— ä¸ªäººå§“名) -->
          <el-table :data="teamPerformanceList" border stripe style="margin-top: 20px;">
            <el-table-column prop="team" label="销售团队" width="140" />
            <el-table-column prop="orderCount" label="订单数" width="100" />
            <el-table-column prop="salesAmount" label="销售额" width="140">
              <template #default="scope">Â¥{{ scope.row.salesAmount.toLocaleString() }}</template>
            </el-table-column>
            <el-table-column prop="shipmentRate" label="发货率" width="100">
              <template #default="scope">{{ scope.row.shipmentRate }}%</template>
            </el-table-column>
            <el-table-column prop="collectionRate" label="回款率" width="100">
              <template #default="scope">{{ scope.row.collectionRate }}%</template>
            </el-table-column>
            <el-table-column prop="attainment" label="目标达成率" width="120">
              <template #default="scope">
                <el-tag :type="scope.row.attainment >= 100 ? 'success' : scope.row.attainment >= 80 ? 'warning' : 'danger'">
                  {{ scope.row.attainment }}%
                </el-tag>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
      </el-tab-pane>
    </el-tabs>
    <!-- ä»·æ ¼ç­–略对话框 -->
@@ -482,7 +600,7 @@
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="策略类型" prop="strategyType">
              <el-select v-model="priceStrategyForm.strategyType" placeholder="请选择策略类型" style="width: 100%;">
              <el-select v-model="priceStrategyForm.strategyType" placeholder="请选择策略类型" style="width: 100%;" :disabled="priceStrategyDialogMode === 'view'">
                <el-option label="专属价格" value="专属价格"></el-option>
                <el-option label="阶梯报价" value="阶梯报价"></el-option>
                <el-option label="促销折扣" value="促销折扣"></el-option>
@@ -491,7 +609,7 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="客户名称" prop="customerName">
              <el-select v-model="priceStrategyForm.customerName" placeholder="请选择客户" style="width: 100%;">
              <el-select v-model="priceStrategyForm.customerName" placeholder="请选择客户" style="width: 100%;" :disabled="priceStrategyDialogMode === 'view'">
                <el-option label="华东建材集团" value="华东建材集团"></el-option>
                <el-option label="长江混凝土公司" value="长江混凝土公司"></el-option>
                <el-option label="浦江水泥制品厂" value="浦江水泥制品厂"></el-option>
@@ -502,7 +620,7 @@
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="产品名称" prop="productName">
              <el-select v-model="priceStrategyForm.productName" placeholder="请选择产品" style="width: 100%;">
              <el-select v-model="priceStrategyForm.productName" placeholder="请选择产品" style="width: 100%;" :disabled="priceStrategyDialogMode === 'view'">
                <el-option label="P.O 42.5普通硅酸盐水泥" value="P.O 42.5普通硅酸盐水泥"></el-option>
                <el-option label="P.S 32.5矿渣硅酸盐水泥" value="P.S 32.5矿渣硅酸盐水泥"></el-option>
                <el-option label="P.C 32.5复合硅酸盐水泥" value="P.C 32.5复合硅酸盐水泥"></el-option>
@@ -511,19 +629,19 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="规格型号" prop="specification">
              <el-input v-model="priceStrategyForm.specification" placeholder="请输入规格型号" />
              <el-input v-model="priceStrategyForm.specification" placeholder="请输入规格型号" :disabled="priceStrategyDialogMode === 'view'" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="基础价格(元/吨)" prop="basePrice">
              <el-input-number v-model="priceStrategyForm.basePrice" :min="0" :precision="2" style="width: 100%;" />
              <el-input-number v-model="priceStrategyForm.basePrice" :min="0" :precision="2" style="width: 100%;" :disabled="priceStrategyDialogMode === 'view'" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="策略价格" prop="strategyPrice">
              <el-input v-model="priceStrategyForm.strategyPrice" placeholder="如: Â¥350/吨 æˆ– 9折" />
              <el-input v-model="priceStrategyForm.strategyPrice" placeholder="如: Â¥350/吨 æˆ– 9折" :disabled="priceStrategyDialogMode === 'view'" />
            </el-form-item>
          </el-col>
        </el-row>
@@ -536,6 +654,7 @@
                placeholder="选择生效日期"
                style="width: 100%"
                value-format="YYYY-MM-DD"
                :disabled="priceStrategyDialogMode === 'view'"
              />
            </el-form-item>
          </el-col>
@@ -547,17 +666,18 @@
                placeholder="选择失效日期"
                style="width: 100%"
                value-format="YYYY-MM-DD"
                :disabled="priceStrategyDialogMode === 'view'"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="策略说明" prop="description">
          <el-input type="textarea" v-model="priceStrategyForm.description" :rows="3" placeholder="请输入策略说明" />
          <el-input type="textarea" v-model="priceStrategyForm.description" :rows="3" placeholder="请输入策略说明" :disabled="priceStrategyDialogMode === 'view'" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="priceStrategyDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSavePriceStrategy">保存</el-button>
        <el-button @click="priceStrategyDialogVisible = false">{{ priceStrategyDialogMode === 'view' ? '关闭' : '取消' }}</el-button>
        <el-button v-if="priceStrategyDialogMode !== 'view'" type="primary" @click="handleSavePriceStrategy">保存</el-button>
      </template>
    </el-dialog>
  </div>
@@ -648,6 +768,7 @@
const priceStrategyDialogVisible = ref(false)
const priceStrategyDialogTitle = ref('新增价格策略')
const priceStrategyDialogMode = ref('add') // add | edit | view
const priceStrategyForm = reactive({
  strategyType: '',
  customerName: '',
@@ -849,16 +970,21 @@
const handleAddPriceStrategy = () => {
  priceStrategyDialogTitle.value = '新增价格策略'
  resetPriceStrategyForm()
  priceStrategyDialogMode.value = 'add'
  priceStrategyDialogVisible.value = true
}
const handleViewPriceStrategy = (row) => {
  ElMessage.info('查看策略详情: ' + row.strategyNo)
  priceStrategyDialogTitle.value = '查看价格策略'
  Object.assign(priceStrategyForm, row)
  priceStrategyDialogMode.value = 'view'
  priceStrategyDialogVisible.value = true
}
const handleEditPriceStrategy = (row) => {
  priceStrategyDialogTitle.value = '编辑价格策略'
  Object.assign(priceStrategyForm, row)
  priceStrategyDialogMode.value = 'edit'
  priceStrategyDialogVisible.value = true
}
@@ -868,6 +994,12 @@
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    // æœ¬åœ°å‡æ•°æ®åˆ é™¤ï¼šä»Žåˆ—表中移除并更新总数
    const index = priceStrategyList.value.findIndex(item => item.id === row.id)
    if (index > -1) {
      priceStrategyList.value.splice(index, 1)
      if (pricePagination.total > 0) pricePagination.total -= 1
    }
    ElMessage.success('删除成功')
  })
}
@@ -1176,6 +1308,112 @@
  profitPagination.pageSize = val.limit
}
// ========== æŒ‡æ ‡ç»Ÿè®¡ï¼ˆå¤šç»´åº¦åˆ†æžï¼‰ ==========
const indicatorKpis = reactive({
  orderCount: 1280,
  salesAmount: 9650000,
  shipmentRate: 89.2,
  collectionRate: 76.4
})
const indicatorFilter = reactive({
  product: '',
  customer: '',
  region: '',
  dateRange: []
})
const indicatorChartRef = ref(null)
let indicatorChart = null
const teamPerformanceList = ref([
  { team: '华东团队A', orderCount: 320, salesAmount: 2850000, shipmentRate: 90, collectionRate: 80, attainment: 105 },
  { team: '华北团队B', orderCount: 280, salesAmount: 2150000, shipmentRate: 86, collectionRate: 73, attainment: 92 },
  { team: '华南团队C', orderCount: 210, salesAmount: 1850000, shipmentRate: 88, collectionRate: 70, attainment: 78 },
  { team: '西南团队D', orderCount: 180, salesAmount: 1500000, shipmentRate: 83, collectionRate: 68, attainment: 74 }
])
const initIndicatorChart = () => {
  if (!indicatorChartRef.value) return
  if (indicatorChart) indicatorChart.dispose()
  indicatorChart = echarts.init(indicatorChartRef.value)
  const option = {
    title: { text: '多维度销售指标趋势', left: 'center' },
    tooltip: { trigger: 'axis' },
    legend: { data: ['订单数', '销售额', '发货率', '回款率'], top: 30 },
    grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
    xAxis: { type: 'category', data: ['2024-12', '2025-01', '2025-02', '2025-03', '2025-04', '2025-05'] },
    yAxis: [
      { type: 'value', name: '数量/金额', axisLabel: { formatter: '{value}' } },
      { type: 'value', name: '比例(%)', min: 0, max: 100, axisLabel: { formatter: '{value}%' } }
    ],
    series: [
      { name: '订单数', type: 'bar', data: [180, 220, 210, 260, 205, 225], itemStyle: { color: '#409eff' } },
      { name: '销售额', type: 'bar', data: [820, 950, 910, 1080, 980, 1020], itemStyle: { color: '#67c23a' } },
      { name: '发货率', type: 'line', yAxisIndex: 1, data: [86, 89, 88, 91, 87, 90], itemStyle: { color: '#e6a23c' } },
      { name: '回款率', type: 'line', yAxisIndex: 1, data: [72, 76, 74, 79, 75, 78], itemStyle: { color: '#f56c6c' } }
    ]
  }
  indicatorChart.setOption(option)
}
const applyIndicatorFilter = () => {
  // ä½¿ç”¨å‡æ•°æ®æ¨¡æ‹ŸæŸ¥è¯¢ï¼Œåˆ·æ–°KPI和图表
  // ä»…演示:随机微调以体现筛选效果
  const random = (base, delta) => {
    const v = base + Math.round((Math.random() - 0.5) * delta)
    return v < 0 ? 0 : v
  }
  indicatorKpis.orderCount = random(1280, 120)
  indicatorKpis.salesAmount = random(9650000, 350000)
  indicatorKpis.shipmentRate = (85 + Math.random() * 10).toFixed(1) * 1
  indicatorKpis.collectionRate = (70 + Math.random() * 12).toFixed(1) * 1
  setTimeout(() => initIndicatorChart(), 200)
}
const resetIndicatorFilter = () => {
  indicatorFilter.product = ''
  indicatorFilter.customer = ''
  indicatorFilter.region = ''
  indicatorFilter.dateRange = []
  applyIndicatorFilter()
}
const exportIndicatorTable = () => {
  // å¯¼å‡ºå›¢é˜Ÿä¸šç»©ä¸ºCSV(假导出)
  const header = ['销售团队', '订单数', '销售额', '发货率(%)', '回款率(%)', '目标达成率(%)']
  const rows = teamPerformanceList.value.map(r => [
    r.team,
    r.orderCount,
    r.salesAmount,
    r.shipmentRate,
    r.collectionRate,
    r.attainment
  ])
  const csv = [header, ...rows].map(r => r.join(',')).join('\n')
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
  const url = URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = '指标统计-团队业绩.csv'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
  URL.revokeObjectURL(url)
}
const exportIndicatorChart = () => {
  if (!indicatorChart) return
  const url = indicatorChart.getDataURL({ type: 'png', pixelRatio: 2, backgroundColor: '#fff' })
  const link = document.createElement('a')
  link.href = url
  link.download = '指标统计-图表.png'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}
// ç”Ÿå‘½å‘¨æœŸ
onMounted(() => {
  // ç»„件挂载后不立即初始化图表,等待用户切换到对应标签页
@@ -1188,6 +1426,8 @@
      initPriceChart()
    } else if (newVal === 'profitAnalysis') {
      initProfitChart()
    } else if (newVal === 'indicatorStats') {
      initIndicatorChart()
    }
  })
})