Commit 64ac7d699557aa04b7992616f2b12d473712f943
1 parent
12ccf031
最新
Showing
14 changed files
with
4049 additions
and
46 deletions
antis-ncc-admin/src/api/extend/headquartersStock.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | + | |
| 3 | +// 获取总部股份统计列表 | |
| 4 | +export function getHeadquartersStockList(params) { | |
| 5 | + return request({ | |
| 6 | + url: '/api/Extend/lqsharestatisticshq/list', | |
| 7 | + method: 'GET', | |
| 8 | + data: params | |
| 9 | + }) | |
| 10 | +} | |
| 11 | + | |
| 12 | +// 生成总部股份统计数据 | |
| 13 | +export function generateHeadquartersStock(data) { | |
| 14 | + return request({ | |
| 15 | + url: '/api/Extend/lqsharestatisticshq/generate', | |
| 16 | + method: 'POST', | |
| 17 | + data: data | |
| 18 | + }) | |
| 19 | +} | |
| 20 | + | ... | ... |
antis-ncc-admin/src/api/extend/shopStock.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | + | |
| 3 | +// 获取门店股份统计列表 | |
| 4 | +export function getShopStockList(params) { | |
| 5 | + return request({ | |
| 6 | + url: '/api/Extend/lqsharestatisticsstore/list', | |
| 7 | + method: 'GET', | |
| 8 | + data: params | |
| 9 | + }) | |
| 10 | +} | |
| 11 | + | |
| 12 | +// 生成门店股份统计数据 | |
| 13 | +export function generateShopStock(data) { | |
| 14 | + return request({ | |
| 15 | + url: '/api/Extend/lqsharestatisticsstore/generate', | |
| 16 | + method: 'POST', | |
| 17 | + data: data | |
| 18 | + }) | |
| 19 | +} | |
| 20 | + | |
| 21 | +// 获取门店下拉框列表 | |
| 22 | +export function getStoreSelector() { | |
| 23 | + return request({ | |
| 24 | + url: '/api/Extend/LqMdxx/Selector', | |
| 25 | + method: 'GET' | |
| 26 | + }) | |
| 27 | +} | |
| 28 | + | ... | ... |
antis-ncc-admin/src/api/extend/techStock.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | + | |
| 3 | +// 获取科技部股份统计列表 | |
| 4 | +export function getTechStockList(params) { | |
| 5 | + return request({ | |
| 6 | + url: '/api/Extend/lqsharestatisticstechdept/list', | |
| 7 | + method: 'GET', | |
| 8 | + data: params | |
| 9 | + }) | |
| 10 | +} | |
| 11 | + | |
| 12 | +// 生成科技部股份统计数据 | |
| 13 | +export function generateTechStock(data) { | |
| 14 | + return request({ | |
| 15 | + url: '/api/Extend/lqsharestatisticstechdept/generate', | |
| 16 | + method: 'POST', | |
| 17 | + data: data | |
| 18 | + }) | |
| 19 | +} | |
| 20 | + | ... | ... |
antis-ncc-admin/src/views/statisticsList/form13.vue
| ... | ... | @@ -209,12 +209,12 @@ |
| 209 | 209 | </el-table-column> |
| 210 | 210 | <el-table-column prop="sourceType" label="合作机构" min-width="100"> |
| 211 | 211 | <template slot-scope="scope"> |
| 212 | - <span>{{ scope.row.paymentMethod == '合作' ? (scope.row.hgjg || '无') : '无' }}</span> | |
| 212 | + <span>{{ scope.row.paymentMethod == '合作' ? (scope.row.hgjgName || '无') : '无' }}</span> | |
| 213 | 213 | </template> |
| 214 | 214 | </el-table-column> |
| 215 | 215 | <el-table-column prop="sourceType" label="结算结构" min-width="100"> |
| 216 | 216 | <template slot-scope="scope"> |
| 217 | - <span>{{ scope.row.paymentMethod != '合作' ? (scope.row.fkyy || '无') : '无' }}</span> | |
| 217 | + <span>{{ scope.row.paymentMethod != '合作' ? (scope.row.fkyyName || '无') : '无' }}</span> | |
| 218 | 218 | </template> |
| 219 | 219 | </el-table-column> |
| 220 | 220 | <el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip> | ... | ... |
antis-ncc-admin/src/views/wageManagement/headquarters-stock-detail-dialog.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + title="总部股份详情" | |
| 4 | + :visible="visible" | |
| 5 | + width="1000px" | |
| 6 | + :close-on-click-modal="false" | |
| 7 | + @close="handleClose" | |
| 8 | + class="detail-dialog" | |
| 9 | + > | |
| 10 | + <div v-if="detailData" class="detail-content"> | |
| 11 | + <!-- 基本信息 --> | |
| 12 | + <div class="detail-section"> | |
| 13 | + <div class="section-title"> | |
| 14 | + <i class="el-icon-user"></i> | |
| 15 | + <span>基本信息</span> | |
| 16 | + </div> | |
| 17 | + <div class="section-content"> | |
| 18 | + <div class="info-row"> | |
| 19 | + <div class="info-item"> | |
| 20 | + <span class="label">统计月份:</span> | |
| 21 | + <span class="value">{{ formatMonth(detailData.StatisticsMonth) || '无' }}</span> | |
| 22 | + </div> | |
| 23 | + <div class="info-item" v-if="detailData.CreateTime"> | |
| 24 | + <span class="label">创建时间:</span> | |
| 25 | + <span class="value">{{ formatDateTime(detailData.CreateTime) }}</span> | |
| 26 | + </div> | |
| 27 | + <div class="info-item" v-if="detailData.UpdateTime"> | |
| 28 | + <span class="label">更新时间:</span> | |
| 29 | + <span class="value">{{ formatDateTime(detailData.UpdateTime) }}</span> | |
| 30 | + </div> | |
| 31 | + </div> | |
| 32 | + </div> | |
| 33 | + </div> | |
| 34 | + | |
| 35 | + <!-- 收入信息 --> | |
| 36 | + <div class="detail-section"> | |
| 37 | + <div class="section-title"> | |
| 38 | + <i class="el-icon-trophy"></i> | |
| 39 | + <span>收入信息</span> | |
| 40 | + </div> | |
| 41 | + <div class="section-content"> | |
| 42 | + <div class="info-row"> | |
| 43 | + <div class="info-item"> | |
| 44 | + <span class="label">收入-全部:</span> | |
| 45 | + <span class="value highlight large">{{ formatMoney(detailData.IncomeGeneral) }}</span> | |
| 46 | + </div> | |
| 47 | + <div class="info-item"> | |
| 48 | + <span class="label">收入-科技部:</span> | |
| 49 | + <span class="value highlight large">{{ formatMoney(detailData.IncomeTechDept) }}</span> | |
| 50 | + </div> | |
| 51 | + </div> | |
| 52 | + </div> | |
| 53 | + </div> | |
| 54 | + | |
| 55 | + <!-- 成本信息 --> | |
| 56 | + <div class="detail-section"> | |
| 57 | + <div class="section-title"> | |
| 58 | + <i class="el-icon-shopping-cart-2"></i> | |
| 59 | + <span>成本信息</span> | |
| 60 | + </div> | |
| 61 | + <div class="section-content"> | |
| 62 | + <div class="info-row"> | |
| 63 | + <div class="info-item"> | |
| 64 | + <span class="label">成本-报销:</span> | |
| 65 | + <span class="value">{{ formatMoney(detailData.CostReimbursement) }}</span> | |
| 66 | + </div> | |
| 67 | + <div class="info-item"> | |
| 68 | + <span class="label">成本-人工:</span> | |
| 69 | + <span class="value">{{ formatMoney(detailData.CostLabor) }}</span> | |
| 70 | + </div> | |
| 71 | + <div class="info-item"> | |
| 72 | + <span class="label">成本-教育部房租:</span> | |
| 73 | + <span class="value">{{ formatMoney(detailData.CostEducationRent) }}</span> | |
| 74 | + </div> | |
| 75 | + <div class="info-item"> | |
| 76 | + <span class="label">成本-仓库房租:</span> | |
| 77 | + <span class="value">{{ formatMoney(detailData.CostWarehouseRent) }}</span> | |
| 78 | + </div> | |
| 79 | + <div class="info-item"> | |
| 80 | + <span class="label">成本-总部房租:</span> | |
| 81 | + <span class="value">{{ formatMoney(detailData.CostHQRent) }}</span> | |
| 82 | + </div> | |
| 83 | + </div> | |
| 84 | + </div> | |
| 85 | + </div> | |
| 86 | + | |
| 87 | + <!-- 利润结果 --> | |
| 88 | + <div class="detail-section"> | |
| 89 | + <div class="section-title"> | |
| 90 | + <i class="el-icon-data-line"></i> | |
| 91 | + <span>利润结果</span> | |
| 92 | + </div> | |
| 93 | + <div class="section-content"> | |
| 94 | + <div class="info-row"> | |
| 95 | + <div class="info-item"> | |
| 96 | + <span class="label">运营利润:</span> | |
| 97 | + <span class="value highlight large profit">{{ formatMoney(detailData.OperationalProfit) }}</span> | |
| 98 | + </div> | |
| 99 | + </div> | |
| 100 | + </div> | |
| 101 | + </div> | |
| 102 | + </div> | |
| 103 | + <div slot="footer" class="dialog-footer"> | |
| 104 | + <el-button @click="handleClose">关闭</el-button> | |
| 105 | + </div> | |
| 106 | + </el-dialog> | |
| 107 | +</template> | |
| 108 | + | |
| 109 | +<script> | |
| 110 | +export default { | |
| 111 | + name: 'HeadquartersStockDetailDialog', | |
| 112 | + props: { | |
| 113 | + visible: { | |
| 114 | + type: Boolean, | |
| 115 | + default: false | |
| 116 | + }, | |
| 117 | + detailData: { | |
| 118 | + type: Object, | |
| 119 | + default: null | |
| 120 | + } | |
| 121 | + }, | |
| 122 | + methods: { | |
| 123 | + handleClose() { | |
| 124 | + this.$emit('close') | |
| 125 | + }, | |
| 126 | + formatMoney(value) { | |
| 127 | + if (value === null || value === undefined || value === '') { | |
| 128 | + return '0.00' | |
| 129 | + } | |
| 130 | + return Number(value).toFixed(2) | |
| 131 | + }, | |
| 132 | + formatMonth(value) { | |
| 133 | + if (!value || value.length !== 6) { | |
| 134 | + return value || '无' | |
| 135 | + } | |
| 136 | + const year = value.substring(0, 4) | |
| 137 | + const month = value.substring(4, 6) | |
| 138 | + return `${year}-${month}` | |
| 139 | + }, | |
| 140 | + formatDateTime(value) { | |
| 141 | + if (!value) return '无' | |
| 142 | + const date = new Date(value) | |
| 143 | + const year = date.getFullYear() | |
| 144 | + const month = String(date.getMonth() + 1).padStart(2, '0') | |
| 145 | + const day = String(date.getDate()).padStart(2, '0') | |
| 146 | + const hours = String(date.getHours()).padStart(2, '0') | |
| 147 | + const minutes = String(date.getMinutes()).padStart(2, '0') | |
| 148 | + const seconds = String(date.getSeconds()).padStart(2, '0') | |
| 149 | + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` | |
| 150 | + } | |
| 151 | + } | |
| 152 | +} | |
| 153 | +</script> | |
| 154 | + | |
| 155 | +<style lang="scss" scoped> | |
| 156 | +.detail-dialog { | |
| 157 | + .detail-content { | |
| 158 | + max-height: 70vh; | |
| 159 | + overflow-y: auto; | |
| 160 | + padding: 20px; | |
| 161 | + } | |
| 162 | + | |
| 163 | + .detail-section { | |
| 164 | + margin-bottom: 24px; | |
| 165 | + background: #f9f9f9; | |
| 166 | + border-radius: 8px; | |
| 167 | + padding: 16px; | |
| 168 | + | |
| 169 | + &:last-child { | |
| 170 | + margin-bottom: 0; | |
| 171 | + } | |
| 172 | + | |
| 173 | + .section-title { | |
| 174 | + display: flex; | |
| 175 | + align-items: center; | |
| 176 | + gap: 8px; | |
| 177 | + margin-bottom: 16px; | |
| 178 | + font-size: 16px; | |
| 179 | + font-weight: 600; | |
| 180 | + color: #303133; | |
| 181 | + border-bottom: 2px solid #409EFF; | |
| 182 | + padding-bottom: 8px; | |
| 183 | + | |
| 184 | + i { | |
| 185 | + color: #409EFF; | |
| 186 | + font-size: 18px; | |
| 187 | + } | |
| 188 | + } | |
| 189 | + | |
| 190 | + .section-content { | |
| 191 | + .info-row { | |
| 192 | + display: flex; | |
| 193 | + flex-wrap: wrap; | |
| 194 | + gap: 20px; | |
| 195 | + | |
| 196 | + .info-item { | |
| 197 | + flex: 0 0 calc(33.333% - 14px); | |
| 198 | + min-width: 250px; | |
| 199 | + display: flex; | |
| 200 | + align-items: center; | |
| 201 | + padding: 8px 12px; | |
| 202 | + background: #fff; | |
| 203 | + border-radius: 4px; | |
| 204 | + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); | |
| 205 | + | |
| 206 | + .label { | |
| 207 | + color: #606266; | |
| 208 | + font-weight: 500; | |
| 209 | + margin-right: 8px; | |
| 210 | + white-space: nowrap; | |
| 211 | + } | |
| 212 | + | |
| 213 | + .value { | |
| 214 | + color: #303133; | |
| 215 | + flex: 1; | |
| 216 | + text-align: right; | |
| 217 | + | |
| 218 | + &.highlight { | |
| 219 | + color: #409EFF; | |
| 220 | + font-weight: 600; | |
| 221 | + } | |
| 222 | + | |
| 223 | + &.large { | |
| 224 | + font-size: 18px; | |
| 225 | + } | |
| 226 | + | |
| 227 | + &.profit { | |
| 228 | + color: #67C23A; | |
| 229 | + } | |
| 230 | + } | |
| 231 | + } | |
| 232 | + } | |
| 233 | + } | |
| 234 | + } | |
| 235 | + | |
| 236 | + .dialog-footer { | |
| 237 | + text-align: right; | |
| 238 | + padding: 20px; | |
| 239 | + border-top: 1px solid #e4e7ed; | |
| 240 | + } | |
| 241 | +} | |
| 242 | + | |
| 243 | +// 滚动条样式 | |
| 244 | +.detail-content::-webkit-scrollbar { | |
| 245 | + width: 6px; | |
| 246 | +} | |
| 247 | + | |
| 248 | +.detail-content::-webkit-scrollbar-track { | |
| 249 | + background: #f1f1f1; | |
| 250 | + border-radius: 3px; | |
| 251 | +} | |
| 252 | + | |
| 253 | +.detail-content::-webkit-scrollbar-thumb { | |
| 254 | + background: #c1c1c1; | |
| 255 | + border-radius: 3px; | |
| 256 | + | |
| 257 | + &:hover { | |
| 258 | + background: #a8a8a8; | |
| 259 | + } | |
| 260 | +} | |
| 261 | +</style> | |
| 262 | + | ... | ... |
antis-ncc-admin/src/views/wageManagement/headquarters-stock.vue
| ... | ... | @@ -8,8 +8,24 @@ |
| 8 | 8 | </div> |
| 9 | 9 | <div class="header-right"> |
| 10 | 10 | <el-button |
| 11 | + type="success" | |
| 12 | + icon="el-icon-download" | |
| 13 | + @click="handleExport" | |
| 14 | + :loading="exportLoading" | |
| 15 | + > | |
| 16 | + 导出 | |
| 17 | + </el-button> | |
| 18 | + <el-button | |
| 19 | + type="primary" | |
| 20 | + icon="el-icon-cpu" | |
| 21 | + @click="showCalculateDialog" | |
| 22 | + :loading="calculateLoading" | |
| 23 | + > | |
| 24 | + 计算股份 | |
| 25 | + </el-button> | |
| 26 | + <el-button | |
| 11 | 27 | icon="el-icon-refresh" |
| 12 | - @click="handleRefresh" | |
| 28 | + @click="getList" | |
| 13 | 29 | :loading="loading" |
| 14 | 30 | > |
| 15 | 31 | 刷新 |
| ... | ... | @@ -17,28 +33,382 @@ |
| 17 | 33 | </div> |
| 18 | 34 | </div> |
| 19 | 35 | |
| 20 | - <!-- 内容区域 --> | |
| 21 | - <div class="content-container"> | |
| 22 | - <!-- 待开发 --> | |
| 36 | + <!-- 搜索区域 --> | |
| 37 | + <div class="search-container"> | |
| 38 | + <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="80px"> | |
| 39 | + <el-form-item label="统计月份" prop="statisticsMonth"> | |
| 40 | + <el-date-picker | |
| 41 | + v-model="queryParams.statisticsMonth" | |
| 42 | + type="month" | |
| 43 | + placeholder="选择月份" | |
| 44 | + format="yyyyMM" | |
| 45 | + value-format="yyyyMM" | |
| 46 | + style="width: 200px" | |
| 47 | + /> | |
| 48 | + </el-form-item> | |
| 49 | + <el-form-item> | |
| 50 | + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> | |
| 51 | + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button> | |
| 52 | + </el-form-item> | |
| 53 | + </el-form> | |
| 23 | 54 | </div> |
| 55 | + | |
| 56 | + <!-- 数据表格 --> | |
| 57 | + <div class="table-container"> | |
| 58 | + <NCC-table | |
| 59 | + v-loading="loading" | |
| 60 | + :data="list" | |
| 61 | + border | |
| 62 | + stripe | |
| 63 | + height="calc(100vh - 420px)" | |
| 64 | + :header-cell-style="{ background: '#f5f7fa', color: '#606266' }" | |
| 65 | + > | |
| 66 | + <!-- 基本信息 --> | |
| 67 | + <el-table-column prop="StatisticsMonth" label="统计月份" width="150" align="center" fixed="left"> | |
| 68 | + <template slot-scope="scope"> | |
| 69 | + <div class="month-name"> | |
| 70 | + <i class="el-icon-date month-icon"></i> | |
| 71 | + <span>{{ formatMonth(scope.row.StatisticsMonth) || '无' }}</span> | |
| 72 | + </div> | |
| 73 | + </template> | |
| 74 | + </el-table-column> | |
| 75 | + | |
| 76 | + <!-- 收入信息 --> | |
| 77 | + <el-table-column label="收入信息" align="center"> | |
| 78 | + <el-table-column prop="IncomeGeneral" label="收入-全部" width="140" align="center"> | |
| 79 | + <template slot-scope="scope"> | |
| 80 | + <span class="highlight">{{ formatMoney(scope.row.IncomeGeneral) }}</span> | |
| 81 | + </template> | |
| 82 | + </el-table-column> | |
| 83 | + <el-table-column prop="IncomeTechDept" label="收入-科技部" width="140" align="center"> | |
| 84 | + <template slot-scope="scope"> | |
| 85 | + <span class="highlight">{{ formatMoney(scope.row.IncomeTechDept) }}</span> | |
| 86 | + </template> | |
| 87 | + </el-table-column> | |
| 88 | + </el-table-column> | |
| 89 | + | |
| 90 | + <!-- 成本信息 --> | |
| 91 | + <el-table-column label="成本信息" align="center"> | |
| 92 | + <el-table-column prop="CostReimbursement" label="成本-报销" width="140" align="center"> | |
| 93 | + <template slot-scope="scope"> | |
| 94 | + <span>{{ formatMoney(scope.row.CostReimbursement) }}</span> | |
| 95 | + </template> | |
| 96 | + </el-table-column> | |
| 97 | + <el-table-column prop="CostLabor" label="成本-人工" width="140" align="center"> | |
| 98 | + <template slot-scope="scope"> | |
| 99 | + <span>{{ formatMoney(scope.row.CostLabor) }}</span> | |
| 100 | + </template> | |
| 101 | + </el-table-column> | |
| 102 | + <el-table-column prop="CostEducationRent" label="成本-教育部房租" width="160" align="center"> | |
| 103 | + <template slot-scope="scope"> | |
| 104 | + <span>{{ formatMoney(scope.row.CostEducationRent) }}</span> | |
| 105 | + </template> | |
| 106 | + </el-table-column> | |
| 107 | + <el-table-column prop="CostWarehouseRent" label="成本-仓库房租" width="160" align="center"> | |
| 108 | + <template slot-scope="scope"> | |
| 109 | + <span>{{ formatMoney(scope.row.CostWarehouseRent) }}</span> | |
| 110 | + </template> | |
| 111 | + </el-table-column> | |
| 112 | + <el-table-column prop="CostHQRent" label="成本-总部房租" width="160" align="center"> | |
| 113 | + <template slot-scope="scope"> | |
| 114 | + <span>{{ formatMoney(scope.row.CostHQRent) }}</span> | |
| 115 | + </template> | |
| 116 | + </el-table-column> | |
| 117 | + </el-table-column> | |
| 118 | + | |
| 119 | + <!-- 利润结果 --> | |
| 120 | + <el-table-column label="利润结果" align="center"> | |
| 121 | + <el-table-column prop="OperationalProfit" label="运营利润" width="140" align="center"> | |
| 122 | + <template slot-scope="scope"> | |
| 123 | + <span class="highlight profit">{{ formatMoney(scope.row.OperationalProfit) }}</span> | |
| 124 | + </template> | |
| 125 | + </el-table-column> | |
| 126 | + </el-table-column> | |
| 127 | + | |
| 128 | + <!-- 操作列 --> | |
| 129 | + <el-table-column label="操作" width="120" align="center" fixed="right"> | |
| 130 | + <template slot-scope="scope"> | |
| 131 | + <el-button | |
| 132 | + type="text" | |
| 133 | + size="mini" | |
| 134 | + icon="el-icon-view" | |
| 135 | + @click="showDetail(scope.row)" | |
| 136 | + > | |
| 137 | + 查看详情 | |
| 138 | + </el-button> | |
| 139 | + </template> | |
| 140 | + </el-table-column> | |
| 141 | + </NCC-table> | |
| 142 | + </div> | |
| 143 | + | |
| 144 | + <!-- 计算股份弹窗 --> | |
| 145 | + <el-dialog | |
| 146 | + title="计算总部股份" | |
| 147 | + :visible="calculateDialogVisible" | |
| 148 | + width="500px" | |
| 149 | + :close-on-click-modal="false" | |
| 150 | + @close="handleCalculateDialogClose" | |
| 151 | + > | |
| 152 | + <el-form label-width="100px" label-position="right"> | |
| 153 | + <el-form-item label="统计月份" required> | |
| 154 | + <el-date-picker | |
| 155 | + v-model="calculateMonth" | |
| 156 | + type="month" | |
| 157 | + placeholder="请选择月份" | |
| 158 | + format="yyyyMM" | |
| 159 | + value-format="yyyyMM" | |
| 160 | + style="width: 100%" | |
| 161 | + /> | |
| 162 | + </el-form-item> | |
| 163 | + </el-form> | |
| 164 | + <div slot="footer" class="dialog-footer"> | |
| 165 | + <el-button @click="handleCalculateDialogClose">取消</el-button> | |
| 166 | + <el-button | |
| 167 | + type="primary" | |
| 168 | + @click="handleCalculateConfirm" | |
| 169 | + :loading="calculateLoading" | |
| 170 | + > | |
| 171 | + 确定 | |
| 172 | + </el-button> | |
| 173 | + </div> | |
| 174 | + </el-dialog> | |
| 175 | + | |
| 176 | + <!-- 详情弹窗 --> | |
| 177 | + <headquarters-stock-detail-dialog | |
| 178 | + :visible="detailVisible" | |
| 179 | + :detail-data="currentDetailData" | |
| 180 | + @close="handleDetailClose" | |
| 181 | + /> | |
| 24 | 182 | </div> |
| 25 | 183 | </template> |
| 26 | 184 | |
| 27 | 185 | <script> |
| 186 | +import { getHeadquartersStockList, generateHeadquartersStock } from '@/api/extend/headquartersStock' | |
| 187 | +import HeadquartersStockDetailDialog from './headquarters-stock-detail-dialog.vue' | |
| 188 | + | |
| 28 | 189 | export default { |
| 29 | 190 | name: 'HeadquartersStock', |
| 191 | + components: { | |
| 192 | + HeadquartersStockDetailDialog | |
| 193 | + }, | |
| 30 | 194 | data() { |
| 195 | + // 获取当前月份 | |
| 196 | + const getCurrentMonth = () => { | |
| 197 | + const now = new Date() | |
| 198 | + const year = now.getFullYear() | |
| 199 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 200 | + return `${year}${month}` | |
| 201 | + } | |
| 202 | + | |
| 31 | 203 | return { |
| 32 | - loading: false | |
| 204 | + loading: false, | |
| 205 | + calculateLoading: false, | |
| 206 | + exportLoading: false, | |
| 207 | + list: [], | |
| 208 | + calculateDialogVisible: false, | |
| 209 | + calculateMonth: getCurrentMonth(), | |
| 210 | + detailVisible: false, | |
| 211 | + currentDetailData: null, | |
| 212 | + queryParams: { | |
| 213 | + statisticsMonth: getCurrentMonth() // yyyyMM 格式 | |
| 214 | + } | |
| 33 | 215 | } |
| 34 | 216 | }, |
| 217 | + created() { | |
| 218 | + this.getList() | |
| 219 | + }, | |
| 35 | 220 | methods: { |
| 36 | - handleRefresh() { | |
| 221 | + // 获取列表数据 | |
| 222 | + async getList() { | |
| 37 | 223 | this.loading = true |
| 38 | - setTimeout(() => { | |
| 224 | + try { | |
| 225 | + const params = { | |
| 226 | + StatisticsMonth: this.queryParams.statisticsMonth || undefined | |
| 227 | + } | |
| 228 | + | |
| 229 | + const response = await getHeadquartersStockList(params) | |
| 230 | + | |
| 231 | + if (response.code === 200) { | |
| 232 | + this.list = response.data.data || [] | |
| 233 | + } else { | |
| 234 | + this.$message.error(response.msg || '获取数据失败') | |
| 235 | + } | |
| 236 | + } catch (error) { | |
| 237 | + console.error('获取总部股份列表失败:', error) | |
| 238 | + this.$message.error('获取数据失败') | |
| 239 | + } finally { | |
| 39 | 240 | this.loading = false |
| 40 | - this.$message.success('刷新成功') | |
| 41 | - }, 500) | |
| 241 | + } | |
| 242 | + }, | |
| 243 | + | |
| 244 | + // 搜索 | |
| 245 | + handleQuery() { | |
| 246 | + this.getList() | |
| 247 | + }, | |
| 248 | + | |
| 249 | + // 重置搜索 | |
| 250 | + resetQuery() { | |
| 251 | + const getCurrentMonth = () => { | |
| 252 | + const now = new Date() | |
| 253 | + const year = now.getFullYear() | |
| 254 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 255 | + return `${year}${month}` | |
| 256 | + } | |
| 257 | + | |
| 258 | + this.queryParams = { | |
| 259 | + statisticsMonth: getCurrentMonth() | |
| 260 | + } | |
| 261 | + this.getList() | |
| 262 | + }, | |
| 263 | + | |
| 264 | + // 显示计算股份弹窗 | |
| 265 | + showCalculateDialog() { | |
| 266 | + const getCurrentMonth = () => { | |
| 267 | + const now = new Date() | |
| 268 | + const year = now.getFullYear() | |
| 269 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 270 | + return `${year}${month}` | |
| 271 | + } | |
| 272 | + this.calculateMonth = getCurrentMonth() | |
| 273 | + this.calculateDialogVisible = true | |
| 274 | + }, | |
| 275 | + | |
| 276 | + // 关闭计算股份弹窗 | |
| 277 | + handleCalculateDialogClose() { | |
| 278 | + this.calculateDialogVisible = false | |
| 279 | + }, | |
| 280 | + | |
| 281 | + // 确认计算股份 | |
| 282 | + async handleCalculateConfirm() { | |
| 283 | + if (!this.calculateMonth) { | |
| 284 | + this.$message.warning('请选择统计月份') | |
| 285 | + return | |
| 286 | + } | |
| 287 | + | |
| 288 | + this.calculateLoading = true | |
| 289 | + try { | |
| 290 | + const data = { | |
| 291 | + statisticsMonth: this.calculateMonth | |
| 292 | + } | |
| 293 | + | |
| 294 | + const response = await generateHeadquartersStock(data) | |
| 295 | + if (response.code === 200) { | |
| 296 | + this.$message.success('计算股份成功') | |
| 297 | + this.calculateDialogVisible = false | |
| 298 | + this.getList() | |
| 299 | + } else { | |
| 300 | + this.$message.error(response.msg || '计算股份失败') | |
| 301 | + } | |
| 302 | + } catch (error) { | |
| 303 | + console.error('计算股份失败:', error) | |
| 304 | + this.$message.error(error.message || '计算股份失败') | |
| 305 | + } finally { | |
| 306 | + this.calculateLoading = false | |
| 307 | + } | |
| 308 | + }, | |
| 309 | + | |
| 310 | + // 显示详情 | |
| 311 | + showDetail(row) { | |
| 312 | + this.currentDetailData = row | |
| 313 | + this.detailVisible = true | |
| 314 | + }, | |
| 315 | + | |
| 316 | + // 关闭详情弹窗 | |
| 317 | + handleDetailClose() { | |
| 318 | + this.detailVisible = false | |
| 319 | + this.currentDetailData = null | |
| 320 | + }, | |
| 321 | + | |
| 322 | + // 导出功能 | |
| 323 | + async handleExport() { | |
| 324 | + if (!this.list || this.list.length === 0) { | |
| 325 | + this.$message.warning('暂无数据可导出') | |
| 326 | + return | |
| 327 | + } | |
| 328 | + | |
| 329 | + this.exportLoading = true | |
| 330 | + try { | |
| 331 | + // 动态导入 xlsx 库 | |
| 332 | + const XLSX = await import('xlsx') | |
| 333 | + | |
| 334 | + // 构建表头(根据后端DTO字段的中文映射) | |
| 335 | + const headers = [ | |
| 336 | + '统计月份', | |
| 337 | + '收入-全部', | |
| 338 | + '收入-科技部', | |
| 339 | + '成本-报销', | |
| 340 | + '成本-人工', | |
| 341 | + '成本-教育部房租', | |
| 342 | + '成本-仓库房租', | |
| 343 | + '成本-总部房租', | |
| 344 | + '运营利润' | |
| 345 | + ] | |
| 346 | + | |
| 347 | + // 构建数据行 | |
| 348 | + const dataRows = this.list.map(item => [ | |
| 349 | + this.formatMonth(item.StatisticsMonth) || '无', | |
| 350 | + this.formatMoney(item.IncomeGeneral), | |
| 351 | + this.formatMoney(item.IncomeTechDept), | |
| 352 | + this.formatMoney(item.CostReimbursement), | |
| 353 | + this.formatMoney(item.CostLabor), | |
| 354 | + this.formatMoney(item.CostEducationRent), | |
| 355 | + this.formatMoney(item.CostWarehouseRent), | |
| 356 | + this.formatMoney(item.CostHQRent), | |
| 357 | + this.formatMoney(item.OperationalProfit) | |
| 358 | + ]) | |
| 359 | + | |
| 360 | + // 合并表头和数据 | |
| 361 | + const excelData = [headers, ...dataRows] | |
| 362 | + | |
| 363 | + // 创建工作表 | |
| 364 | + const ws = XLSX.utils.aoa_to_sheet(excelData) | |
| 365 | + | |
| 366 | + // 设置列宽 | |
| 367 | + const colWidths = headers.map(() => ({ wch: 15 })) | |
| 368 | + ws['!cols'] = colWidths | |
| 369 | + | |
| 370 | + // 创建工作簿 | |
| 371 | + const wb = XLSX.utils.book_new() | |
| 372 | + XLSX.utils.book_append_sheet(wb, ws, '总部股份') | |
| 373 | + | |
| 374 | + // 生成文件名 | |
| 375 | + const now = new Date() | |
| 376 | + const timestamp = now.getFullYear() + | |
| 377 | + String(now.getMonth() + 1).padStart(2, '0') + | |
| 378 | + String(now.getDate()).padStart(2, '0') + | |
| 379 | + String(now.getHours()).padStart(2, '0') + | |
| 380 | + String(now.getMinutes()).padStart(2, '0') + | |
| 381 | + String(now.getSeconds()).padStart(2, '0') | |
| 382 | + const fileName = `总部股份_${timestamp}.xlsx` | |
| 383 | + | |
| 384 | + // 导出文件 | |
| 385 | + XLSX.writeFile(wb, fileName) | |
| 386 | + | |
| 387 | + this.$message.success('导出成功') | |
| 388 | + } catch (error) { | |
| 389 | + console.error('导出失败:', error) | |
| 390 | + this.$message.error('导出失败,请重试') | |
| 391 | + } finally { | |
| 392 | + this.exportLoading = false | |
| 393 | + } | |
| 394 | + }, | |
| 395 | + | |
| 396 | + // 格式化金额 | |
| 397 | + formatMoney(value) { | |
| 398 | + if (value === null || value === undefined || value === '') { | |
| 399 | + return '0.00' | |
| 400 | + } | |
| 401 | + return Number(value).toFixed(2) | |
| 402 | + }, | |
| 403 | + | |
| 404 | + // 格式化月份 | |
| 405 | + formatMonth(value) { | |
| 406 | + if (!value || value.length !== 6) { | |
| 407 | + return value || '无' | |
| 408 | + } | |
| 409 | + const year = value.substring(0, 4) | |
| 410 | + const month = value.substring(4, 6) | |
| 411 | + return `${year}-${month}` | |
| 42 | 412 | } |
| 43 | 413 | } |
| 44 | 414 | } |
| ... | ... | @@ -81,12 +451,58 @@ export default { |
| 81 | 451 | } |
| 82 | 452 | } |
| 83 | 453 | |
| 84 | -.content-container { | |
| 454 | +.search-container { | |
| 455 | + margin-bottom: 20px; | |
| 85 | 456 | padding: 20px; |
| 86 | 457 | background: #fff; |
| 87 | 458 | border-radius: 8px; |
| 88 | 459 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| 89 | - min-height: 400px; | |
| 90 | 460 | } |
| 91 | -</style> | |
| 92 | 461 | |
| 462 | +.table-container { | |
| 463 | + margin-bottom: 20px; | |
| 464 | + padding: 20px; | |
| 465 | + background: #fff; | |
| 466 | + border-radius: 8px; | |
| 467 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| 468 | +} | |
| 469 | + | |
| 470 | +.month-name { | |
| 471 | + display: flex; | |
| 472 | + align-items: center; | |
| 473 | + gap: 6px; | |
| 474 | + | |
| 475 | + .month-icon { | |
| 476 | + color: #409EFF; | |
| 477 | + font-size: 16px; | |
| 478 | + } | |
| 479 | +} | |
| 480 | + | |
| 481 | +.highlight { | |
| 482 | + color: #409EFF; | |
| 483 | + font-weight: 600; | |
| 484 | +} | |
| 485 | + | |
| 486 | +.profit { | |
| 487 | + color: #67C23A; | |
| 488 | +} | |
| 489 | + | |
| 490 | +// 表格样式优化 | |
| 491 | +::v-deep .el-table { | |
| 492 | + .el-table__header-wrapper { | |
| 493 | + th { | |
| 494 | + background-color: #f5f7fa; | |
| 495 | + color: #606266; | |
| 496 | + font-weight: 600; | |
| 497 | + } | |
| 498 | + } | |
| 499 | + | |
| 500 | + .el-table__body-wrapper { | |
| 501 | + .el-table__row { | |
| 502 | + &:hover { | |
| 503 | + background-color: #f5f7fa; | |
| 504 | + } | |
| 505 | + } | |
| 506 | + } | |
| 507 | +} | |
| 508 | +</style> | ... | ... |
antis-ncc-admin/src/views/wageManagement/major-project-director-detail-dialog.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + title="大项目主管工资详情" | |
| 4 | + :visible="visible" | |
| 5 | + width="1400px" | |
| 6 | + :close-on-click-modal="false" | |
| 7 | + @close="handleClose" | |
| 8 | + class="detail-dialog" | |
| 9 | + > | |
| 10 | + <div v-if="detailData" class="detail-content"> | |
| 11 | + <!-- 基本信息 --> | |
| 12 | + <div class="detail-section"> | |
| 13 | + <div class="section-title"> | |
| 14 | + <i class="el-icon-user"></i> | |
| 15 | + <span>基本信息</span> | |
| 16 | + </div> | |
| 17 | + <div class="section-content"> | |
| 18 | + <div class="info-row"> | |
| 19 | + <div class="info-item"> | |
| 20 | + <span class="label">员工姓名:</span> | |
| 21 | + <span class="value">{{ detailData.EmployeeName || '无' }}</span> | |
| 22 | + </div> | |
| 23 | + <div class="info-item"> | |
| 24 | + <span class="label">员工账号:</span> | |
| 25 | + <span class="value">{{ detailData.EmployeeAccount || '无' }}</span> | |
| 26 | + </div> | |
| 27 | + <div class="info-item"> | |
| 28 | + <span class="label">核算岗位:</span> | |
| 29 | + <span class="value">{{ detailData.Position || '无' }}</span> | |
| 30 | + </div> | |
| 31 | + <div class="info-item"> | |
| 32 | + <span class="label">统计月份:</span> | |
| 33 | + <span class="value">{{ detailData.StatisticsMonth || '无' }}</span> | |
| 34 | + </div> | |
| 35 | + <div class="info-item" v-if="detailData.IsTerminated !== undefined && detailData.IsTerminated !== null"> | |
| 36 | + <span class="label">是否离职:</span> | |
| 37 | + <el-tag :type="detailData.IsTerminated === 1 ? 'danger' : 'success'" size="mini"> | |
| 38 | + {{ detailData.IsTerminated === 1 ? '已离职' : '在职' }} | |
| 39 | + </el-tag> | |
| 40 | + </div> | |
| 41 | + <div class="info-item" v-if="detailData.IsLocked !== undefined && detailData.IsLocked !== null"> | |
| 42 | + <span class="label">锁定状态:</span> | |
| 43 | + <el-tag :type="detailData.IsLocked === 1 ? 'danger' : 'success'" size="mini"> | |
| 44 | + {{ detailData.IsLocked === 1 ? '已锁定' : '未锁定' }} | |
| 45 | + </el-tag> | |
| 46 | + </div> | |
| 47 | + </div> | |
| 48 | + </div> | |
| 49 | + </div> | |
| 50 | + | |
| 51 | + <!-- 业绩信息 --> | |
| 52 | + <div class="detail-section"> | |
| 53 | + <div class="section-title"> | |
| 54 | + <i class="el-icon-trophy"></i> | |
| 55 | + <span>业绩信息</span> | |
| 56 | + </div> | |
| 57 | + <div class="section-content"> | |
| 58 | + <div class="info-row"> | |
| 59 | + <div class="info-item"> | |
| 60 | + <span class="label">开单金额:</span> | |
| 61 | + <span class="value">{{ formatMoney(detailData.BillingAmount) }}</span> | |
| 62 | + </div> | |
| 63 | + <div class="info-item"> | |
| 64 | + <span class="label">退卡金额:</span> | |
| 65 | + <span class="value">{{ formatMoney(detailData.RefundAmount) }}</span> | |
| 66 | + </div> | |
| 67 | + <div class="info-item"> | |
| 68 | + <span class="label">总业绩:</span> | |
| 69 | + <span class="value highlight">{{ formatMoney(detailData.TotalPerformance) }}</span> | |
| 70 | + </div> | |
| 71 | + </div> | |
| 72 | + </div> | |
| 73 | + </div> | |
| 74 | + | |
| 75 | + <!-- 提成信息 --> | |
| 76 | + <div class="detail-section"> | |
| 77 | + <div class="section-title"> | |
| 78 | + <i class="el-icon-money"></i> | |
| 79 | + <span>提成信息</span> | |
| 80 | + </div> | |
| 81 | + <div class="section-content"> | |
| 82 | + <div class="info-row"> | |
| 83 | + <div class="info-item"> | |
| 84 | + <span class="label">提成比例:</span> | |
| 85 | + <span class="value">{{ formatPercent(detailData.CommissionRate) }}</span> | |
| 86 | + </div> | |
| 87 | + <div class="info-item"> | |
| 88 | + <span class="label">提成金额:</span> | |
| 89 | + <span class="value highlight">{{ formatMoney(detailData.CommissionAmount) }}</span> | |
| 90 | + </div> | |
| 91 | + </div> | |
| 92 | + </div> | |
| 93 | + </div> | |
| 94 | + | |
| 95 | + <!-- 工资信息 --> | |
| 96 | + <div class="detail-section"> | |
| 97 | + <div class="section-title"> | |
| 98 | + <i class="el-icon-wallet"></i> | |
| 99 | + <span>工资信息</span> | |
| 100 | + </div> | |
| 101 | + <div class="section-content"> | |
| 102 | + <div class="info-row"> | |
| 103 | + <div class="info-item"> | |
| 104 | + <span class="label">底薪:</span> | |
| 105 | + <span class="value">{{ formatMoney(detailData.BaseSalary) }}</span> | |
| 106 | + </div> | |
| 107 | + <div class="info-item"> | |
| 108 | + <span class="label">在店天数:</span> | |
| 109 | + <span class="value">{{ detailData.WorkingDays || '0' }}</span> | |
| 110 | + </div> | |
| 111 | + <div class="info-item"> | |
| 112 | + <span class="label">请假天数:</span> | |
| 113 | + <span class="value">{{ detailData.LeaveDays || '0' }}</span> | |
| 114 | + </div> | |
| 115 | + <div class="info-item"> | |
| 116 | + <span class="label">核算应发工资:</span> | |
| 117 | + <span class="value highlight">{{ formatMoney(detailData.CalculatedGrossSalary) }}</span> | |
| 118 | + </div> | |
| 119 | + <div class="info-item"> | |
| 120 | + <span class="label">最终应发工资:</span> | |
| 121 | + <span class="value highlight">{{ formatMoney(detailData.FinalGrossSalary) }}</span> | |
| 122 | + </div> | |
| 123 | + </div> | |
| 124 | + </div> | |
| 125 | + </div> | |
| 126 | + | |
| 127 | + <!-- 补贴信息 --> | |
| 128 | + <div class="detail-section"> | |
| 129 | + <div class="section-title"> | |
| 130 | + <i class="el-icon-circle-plus"></i> | |
| 131 | + <span>补贴信息</span> | |
| 132 | + </div> | |
| 133 | + <div class="section-content"> | |
| 134 | + <div class="info-row"> | |
| 135 | + <div class="info-item"> | |
| 136 | + <span class="label">当月培训补贴:</span> | |
| 137 | + <span class="value">{{ formatMoney(detailData.MonthlyTrainingSubsidy) }}</span> | |
| 138 | + </div> | |
| 139 | + <div class="info-item"> | |
| 140 | + <span class="label">当月交通补贴:</span> | |
| 141 | + <span class="value">{{ formatMoney(detailData.MonthlyTransportSubsidy) }}</span> | |
| 142 | + </div> | |
| 143 | + <div class="info-item"> | |
| 144 | + <span class="label">上月培训补贴:</span> | |
| 145 | + <span class="value">{{ formatMoney(detailData.LastMonthTrainingSubsidy) }}</span> | |
| 146 | + </div> | |
| 147 | + <div class="info-item"> | |
| 148 | + <span class="label">上月交通补贴:</span> | |
| 149 | + <span class="value">{{ formatMoney(detailData.LastMonthTransportSubsidy) }}</span> | |
| 150 | + </div> | |
| 151 | + <div class="info-item"> | |
| 152 | + <span class="label">补贴合计:</span> | |
| 153 | + <span class="value highlight">{{ formatMoney(detailData.TotalSubsidy) }}</span> | |
| 154 | + </div> | |
| 155 | + </div> | |
| 156 | + </div> | |
| 157 | + </div> | |
| 158 | + | |
| 159 | + <!-- 扣款信息 --> | |
| 160 | + <div class="detail-section"> | |
| 161 | + <div class="section-title"> | |
| 162 | + <i class="el-icon-circle-minus"></i> | |
| 163 | + <span>扣款信息</span> | |
| 164 | + </div> | |
| 165 | + <div class="section-content"> | |
| 166 | + <div class="info-row"> | |
| 167 | + <div class="info-item"> | |
| 168 | + <span class="label">缺卡扣款:</span> | |
| 169 | + <span class="value">{{ formatMoney(detailData.MissingCard) }}</span> | |
| 170 | + </div> | |
| 171 | + <div class="info-item"> | |
| 172 | + <span class="label">迟到扣款:</span> | |
| 173 | + <span class="value">{{ formatMoney(detailData.LateArrival) }}</span> | |
| 174 | + </div> | |
| 175 | + <div class="info-item"> | |
| 176 | + <span class="label">请假扣款:</span> | |
| 177 | + <span class="value">{{ formatMoney(detailData.LeaveDeduction) }}</span> | |
| 178 | + </div> | |
| 179 | + <div class="info-item"> | |
| 180 | + <span class="label">扣社保:</span> | |
| 181 | + <span class="value">{{ formatMoney(detailData.SocialInsuranceDeduction) }}</span> | |
| 182 | + </div> | |
| 183 | + <div class="info-item"> | |
| 184 | + <span class="label">扣除奖励:</span> | |
| 185 | + <span class="value">{{ formatMoney(detailData.RewardDeduction) }}</span> | |
| 186 | + </div> | |
| 187 | + <div class="info-item"> | |
| 188 | + <span class="label">扣住宿费:</span> | |
| 189 | + <span class="value">{{ formatMoney(detailData.AccommodationDeduction) }}</span> | |
| 190 | + </div> | |
| 191 | + <div class="info-item"> | |
| 192 | + <span class="label">扣学习期费用:</span> | |
| 193 | + <span class="value">{{ formatMoney(detailData.StudyPeriodDeduction) }}</span> | |
| 194 | + </div> | |
| 195 | + <div class="info-item"> | |
| 196 | + <span class="label">扣工作服费用:</span> | |
| 197 | + <span class="value">{{ formatMoney(detailData.WorkClothesDeduction) }}</span> | |
| 198 | + </div> | |
| 199 | + <div class="info-item"> | |
| 200 | + <span class="label">扣款合计:</span> | |
| 201 | + <span class="value highlight">{{ formatMoney(detailData.TotalDeduction) }}</span> | |
| 202 | + </div> | |
| 203 | + </div> | |
| 204 | + </div> | |
| 205 | + </div> | |
| 206 | + | |
| 207 | + <!-- 其他信息 --> | |
| 208 | + <div class="detail-section"> | |
| 209 | + <div class="section-title"> | |
| 210 | + <i class="el-icon-document"></i> | |
| 211 | + <span>其他信息</span> | |
| 212 | + </div> | |
| 213 | + <div class="section-content"> | |
| 214 | + <div class="info-row"> | |
| 215 | + <div class="info-item"> | |
| 216 | + <span class="label">发奖金:</span> | |
| 217 | + <span class="value">{{ formatMoney(detailData.Bonus) }}</span> | |
| 218 | + </div> | |
| 219 | + <div class="info-item"> | |
| 220 | + <span class="label">退手机押金:</span> | |
| 221 | + <span class="value">{{ formatMoney(detailData.ReturnPhoneDeposit) }}</span> | |
| 222 | + </div> | |
| 223 | + <div class="info-item"> | |
| 224 | + <span class="label">退住宿押金:</span> | |
| 225 | + <span class="value">{{ formatMoney(detailData.ReturnAccommodationDeposit) }}</span> | |
| 226 | + </div> | |
| 227 | + <div class="info-item"> | |
| 228 | + <span class="label">补发上月:</span> | |
| 229 | + <span class="value">{{ formatMoney(detailData.LastMonthSupplement) }}</span> | |
| 230 | + </div> | |
| 231 | + </div> | |
| 232 | + </div> | |
| 233 | + </div> | |
| 234 | + | |
| 235 | + <!-- 支付信息 --> | |
| 236 | + <div class="detail-section"> | |
| 237 | + <div class="section-title"> | |
| 238 | + <i class="el-icon-credit-card"></i> | |
| 239 | + <span>支付信息</span> | |
| 240 | + </div> | |
| 241 | + <div class="section-content"> | |
| 242 | + <div class="info-row"> | |
| 243 | + <div class="info-item"> | |
| 244 | + <span class="label">实发工资:</span> | |
| 245 | + <span class="value highlight large">{{ formatMoney(detailData.ActualSalary) }}</span> | |
| 246 | + </div> | |
| 247 | + <div class="info-item"> | |
| 248 | + <span class="label">当月是否发放:</span> | |
| 249 | + <span class="value">{{ detailData.MonthlyPaymentStatus || '无' }}</span> | |
| 250 | + </div> | |
| 251 | + <div class="info-item"> | |
| 252 | + <span class="label">支付金额:</span> | |
| 253 | + <span class="value">{{ formatMoney(detailData.PaidAmount) }}</span> | |
| 254 | + </div> | |
| 255 | + <div class="info-item"> | |
| 256 | + <span class="label">待支付金额:</span> | |
| 257 | + <span class="value">{{ formatMoney(detailData.PendingAmount) }}</span> | |
| 258 | + </div> | |
| 259 | + <div class="info-item"> | |
| 260 | + <span class="label">当月支付总额:</span> | |
| 261 | + <span class="value highlight">{{ formatMoney(detailData.MonthlyTotalPayment) }}</span> | |
| 262 | + </div> | |
| 263 | + </div> | |
| 264 | + </div> | |
| 265 | + </div> | |
| 266 | + </div> | |
| 267 | + | |
| 268 | + <div v-else class="no-data"> | |
| 269 | + <i class="el-icon-warning"></i> | |
| 270 | + <span>暂无数据</span> | |
| 271 | + </div> | |
| 272 | + </el-dialog> | |
| 273 | +</template> | |
| 274 | + | |
| 275 | +<script> | |
| 276 | +export default { | |
| 277 | + name: 'MajorProjectDirectorDetailDialog', | |
| 278 | + props: { | |
| 279 | + visible: { | |
| 280 | + type: Boolean, | |
| 281 | + default: false | |
| 282 | + }, | |
| 283 | + detailData: { | |
| 284 | + type: Object, | |
| 285 | + default: null | |
| 286 | + } | |
| 287 | + }, | |
| 288 | + methods: { | |
| 289 | + handleClose() { | |
| 290 | + this.$emit('update:visible', false) | |
| 291 | + this.$emit('close') | |
| 292 | + }, | |
| 293 | + formatMoney(value) { | |
| 294 | + if (value === null || value === undefined || value === '') { | |
| 295 | + return '0.00' | |
| 296 | + } | |
| 297 | + return Number(value).toFixed(2) | |
| 298 | + }, | |
| 299 | + formatPercent(value) { | |
| 300 | + if (value === null || value === undefined || value === '') { | |
| 301 | + return '0.00%' | |
| 302 | + } | |
| 303 | + return (Number(value) * 100).toFixed(2) + '%' | |
| 304 | + } | |
| 305 | + } | |
| 306 | +} | |
| 307 | +</script> | |
| 308 | + | |
| 309 | +<style lang="scss" scoped> | |
| 310 | +.detail-dialog { | |
| 311 | + .detail-content { | |
| 312 | + max-height: 70vh; | |
| 313 | + overflow-y: auto; | |
| 314 | + padding-right: 10px; | |
| 315 | + } | |
| 316 | + | |
| 317 | + .detail-section { | |
| 318 | + margin-bottom: 20px; | |
| 319 | + background: #fff; | |
| 320 | + border-radius: 8px; | |
| 321 | + padding: 20px; | |
| 322 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| 323 | + | |
| 324 | + .section-title { | |
| 325 | + display: flex; | |
| 326 | + align-items: center; | |
| 327 | + gap: 8px; | |
| 328 | + margin-bottom: 16px; | |
| 329 | + padding-bottom: 12px; | |
| 330 | + border-bottom: 2px solid #409EFF; | |
| 331 | + font-size: 16px; | |
| 332 | + font-weight: 600; | |
| 333 | + color: #303133; | |
| 334 | + | |
| 335 | + i { | |
| 336 | + color: #409EFF; | |
| 337 | + font-size: 18px; | |
| 338 | + } | |
| 339 | + } | |
| 340 | + | |
| 341 | + .section-content { | |
| 342 | + .info-row { | |
| 343 | + display: flex; | |
| 344 | + flex-wrap: wrap; | |
| 345 | + gap: 20px 40px; | |
| 346 | + | |
| 347 | + .info-item { | |
| 348 | + display: flex; | |
| 349 | + align-items: center; | |
| 350 | + min-width: 200px; | |
| 351 | + flex: 0 0 calc(33.333% - 27px); | |
| 352 | + | |
| 353 | + .label { | |
| 354 | + color: #606266; | |
| 355 | + font-size: 14px; | |
| 356 | + white-space: nowrap; | |
| 357 | + margin-right: 8px; | |
| 358 | + } | |
| 359 | + | |
| 360 | + .value { | |
| 361 | + color: #303133; | |
| 362 | + font-size: 14px; | |
| 363 | + font-weight: 500; | |
| 364 | + | |
| 365 | + &.highlight { | |
| 366 | + color: #409EFF; | |
| 367 | + font-weight: 600; | |
| 368 | + } | |
| 369 | + | |
| 370 | + &.large { | |
| 371 | + font-size: 18px; | |
| 372 | + color: #67C23A; | |
| 373 | + } | |
| 374 | + } | |
| 375 | + } | |
| 376 | + } | |
| 377 | + } | |
| 378 | + } | |
| 379 | + | |
| 380 | + .no-data { | |
| 381 | + display: flex; | |
| 382 | + flex-direction: column; | |
| 383 | + align-items: center; | |
| 384 | + justify-content: center; | |
| 385 | + padding: 60px 20px; | |
| 386 | + color: #909399; | |
| 387 | + | |
| 388 | + i { | |
| 389 | + font-size: 48px; | |
| 390 | + margin-bottom: 16px; | |
| 391 | + } | |
| 392 | + | |
| 393 | + span { | |
| 394 | + font-size: 14px; | |
| 395 | + } | |
| 396 | + } | |
| 397 | +} | |
| 398 | + | |
| 399 | +// 滚动条样式 | |
| 400 | +.detail-content::-webkit-scrollbar { | |
| 401 | + width: 6px; | |
| 402 | +} | |
| 403 | + | |
| 404 | +.detail-content::-webkit-scrollbar-track { | |
| 405 | + background: #f1f1f1; | |
| 406 | + border-radius: 3px; | |
| 407 | +} | |
| 408 | + | |
| 409 | +.detail-content::-webkit-scrollbar-thumb { | |
| 410 | + background: #c1c1c1; | |
| 411 | + border-radius: 3px; | |
| 412 | + | |
| 413 | + &:hover { | |
| 414 | + background: #a8a8a8; | |
| 415 | + } | |
| 416 | +} | |
| 417 | +</style> | |
| 418 | + | ... | ... |
antis-ncc-admin/src/views/wageManagement/major-project-directors.vue
| ... | ... | @@ -8,6 +8,14 @@ |
| 8 | 8 | </div> |
| 9 | 9 | <div class="header-right"> |
| 10 | 10 | <el-button |
| 11 | + type="success" | |
| 12 | + icon="el-icon-download" | |
| 13 | + @click="handleExport" | |
| 14 | + :loading="exportLoading" | |
| 15 | + > | |
| 16 | + 导出 | |
| 17 | + </el-button> | |
| 18 | + <el-button | |
| 11 | 19 | type="primary" |
| 12 | 20 | icon="el-icon-cpu" |
| 13 | 21 | @click="showCalculateDialog" |
| ... | ... | @@ -289,18 +297,27 @@ |
| 289 | 297 | </el-table-column> |
| 290 | 298 | </el-table-column> |
| 291 | 299 | |
| 292 | - <!-- 其他字段 --> | |
| 293 | - <el-table-column prop="StoreDetail" label="门店明细" width="200" align="center" fixed="right"> | |
| 300 | + <!-- 操作列 --> | |
| 301 | + <el-table-column label="操作" width="200" align="center" fixed="right"> | |
| 294 | 302 | <template slot-scope="scope"> |
| 295 | 303 | <el-button |
| 296 | 304 | type="text" |
| 297 | 305 | size="mini" |
| 306 | + icon="el-icon-view" | |
| 307 | + @click="showDetail(scope.row)" | |
| 308 | + > | |
| 309 | + 查看详情 | |
| 310 | + </el-button> | |
| 311 | + <el-button | |
| 312 | + type="text" | |
| 313 | + size="mini" | |
| 314 | + icon="el-icon-document" | |
| 298 | 315 | @click="showStoreDetail(scope.row)" |
| 299 | 316 | v-if="scope.row.StoreDetail" |
| 317 | + style="margin-left: 8px;" | |
| 300 | 318 | > |
| 301 | - 查看明细 | |
| 319 | + 门店明细 | |
| 302 | 320 | </el-button> |
| 303 | - <span v-else>无</span> | |
| 304 | 321 | </template> |
| 305 | 322 | </el-table-column> |
| 306 | 323 | </NCC-table> |
| ... | ... | @@ -348,6 +365,13 @@ |
| 348 | 365 | </div> |
| 349 | 366 | </el-dialog> |
| 350 | 367 | |
| 368 | + <!-- 详情弹窗 --> | |
| 369 | + <major-project-director-detail-dialog | |
| 370 | + :visible="detailVisible" | |
| 371 | + :detail-data="currentDetailData" | |
| 372 | + @close="handleDetailClose" | |
| 373 | + /> | |
| 374 | + | |
| 351 | 375 | <!-- 门店明细弹窗 --> |
| 352 | 376 | <el-dialog |
| 353 | 377 | title="门店明细" |
| ... | ... | @@ -382,9 +406,13 @@ |
| 382 | 406 | |
| 383 | 407 | <script> |
| 384 | 408 | import { getMajorProjectDirectorSalaryList, calculateMajorProjectDirectorSalary } from '@/api/extend/majorProjectDirectorSalary' |
| 409 | +import MajorProjectDirectorDetailDialog from './major-project-director-detail-dialog.vue' | |
| 385 | 410 | |
| 386 | 411 | export default { |
| 387 | 412 | name: 'MajorProjectDirectorSalary', |
| 413 | + components: { | |
| 414 | + MajorProjectDirectorDetailDialog | |
| 415 | + }, | |
| 388 | 416 | data() { |
| 389 | 417 | // 获取当前年月 |
| 390 | 418 | const getCurrentYear = () => { |
| ... | ... | @@ -400,11 +428,14 @@ export default { |
| 400 | 428 | return { |
| 401 | 429 | loading: false, |
| 402 | 430 | calculateLoading: false, |
| 431 | + exportLoading: false, | |
| 403 | 432 | list: [], |
| 404 | 433 | total: 0, |
| 405 | 434 | calculateDialogVisible: false, |
| 406 | 435 | calculateYear: getCurrentYear(), |
| 407 | 436 | calculateMonth: getCurrentMonth(), |
| 437 | + detailVisible: false, | |
| 438 | + currentDetailData: null, | |
| 408 | 439 | storeDetailVisible: false, |
| 409 | 440 | storeDetailList: [], |
| 410 | 441 | queryParams: { |
| ... | ... | @@ -575,6 +606,152 @@ export default { |
| 575 | 606 | this.storeDetailList = [] |
| 576 | 607 | }, |
| 577 | 608 | |
| 609 | + // 显示详情 | |
| 610 | + showDetail(row) { | |
| 611 | + this.currentDetailData = row | |
| 612 | + this.detailVisible = true | |
| 613 | + }, | |
| 614 | + | |
| 615 | + // 关闭详情弹窗 | |
| 616 | + handleDetailClose() { | |
| 617 | + this.detailVisible = false | |
| 618 | + this.currentDetailData = null | |
| 619 | + }, | |
| 620 | + | |
| 621 | + // 导出功能 | |
| 622 | + async handleExport() { | |
| 623 | + if (!this.list || this.list.length === 0) { | |
| 624 | + this.$message.warning('暂无数据可导出') | |
| 625 | + return | |
| 626 | + } | |
| 627 | + | |
| 628 | + this.exportLoading = true | |
| 629 | + try { | |
| 630 | + // 动态导入 xlsx 库 | |
| 631 | + const XLSX = await import('xlsx') | |
| 632 | + | |
| 633 | + // 构建表头(根据后端DTO字段的中文映射) | |
| 634 | + const headers = [ | |
| 635 | + '员工姓名', | |
| 636 | + '员工账号', | |
| 637 | + '核算岗位', | |
| 638 | + '统计月份', | |
| 639 | + '是否离职', | |
| 640 | + '开单金额', | |
| 641 | + '退卡金额', | |
| 642 | + '总业绩', | |
| 643 | + '底薪', | |
| 644 | + '提成比例', | |
| 645 | + '提成金额', | |
| 646 | + '在店天数', | |
| 647 | + '请假天数', | |
| 648 | + '核算应发工资', | |
| 649 | + '最终应发工资', | |
| 650 | + '当月培训补贴', | |
| 651 | + '当月交通补贴', | |
| 652 | + '上月培训补贴', | |
| 653 | + '上月交通补贴', | |
| 654 | + '补贴合计', | |
| 655 | + '缺卡扣款', | |
| 656 | + '迟到扣款', | |
| 657 | + '请假扣款', | |
| 658 | + '扣社保', | |
| 659 | + '扣除奖励', | |
| 660 | + '扣住宿费', | |
| 661 | + '扣学习期费用', | |
| 662 | + '扣工作服费用', | |
| 663 | + '扣款合计', | |
| 664 | + '发奖金', | |
| 665 | + '退手机押金', | |
| 666 | + '退住宿押金', | |
| 667 | + '补发上月', | |
| 668 | + '实发工资', | |
| 669 | + '当月是否发放', | |
| 670 | + '支付金额', | |
| 671 | + '待支付金额', | |
| 672 | + '当月支付总额', | |
| 673 | + '是否锁定' | |
| 674 | + ] | |
| 675 | + | |
| 676 | + // 构建数据行 | |
| 677 | + const dataRows = this.list.map(item => [ | |
| 678 | + item.EmployeeName || '无', | |
| 679 | + item.EmployeeAccount || '无', | |
| 680 | + item.Position || '无', | |
| 681 | + item.StatisticsMonth || '无', | |
| 682 | + item.IsTerminated === 1 ? '已离职' : '在职', | |
| 683 | + this.formatMoney(item.BillingAmount), | |
| 684 | + this.formatMoney(item.RefundAmount), | |
| 685 | + this.formatMoney(item.TotalPerformance), | |
| 686 | + this.formatMoney(item.BaseSalary), | |
| 687 | + this.formatPercent(item.CommissionRate), | |
| 688 | + this.formatMoney(item.CommissionAmount), | |
| 689 | + item.WorkingDays || '0', | |
| 690 | + item.LeaveDays || '0', | |
| 691 | + this.formatMoney(item.CalculatedGrossSalary), | |
| 692 | + this.formatMoney(item.FinalGrossSalary), | |
| 693 | + this.formatMoney(item.MonthlyTrainingSubsidy), | |
| 694 | + this.formatMoney(item.MonthlyTransportSubsidy), | |
| 695 | + this.formatMoney(item.LastMonthTrainingSubsidy), | |
| 696 | + this.formatMoney(item.LastMonthTransportSubsidy), | |
| 697 | + this.formatMoney(item.TotalSubsidy), | |
| 698 | + this.formatMoney(item.MissingCard), | |
| 699 | + this.formatMoney(item.LateArrival), | |
| 700 | + this.formatMoney(item.LeaveDeduction), | |
| 701 | + this.formatMoney(item.SocialInsuranceDeduction), | |
| 702 | + this.formatMoney(item.RewardDeduction), | |
| 703 | + this.formatMoney(item.AccommodationDeduction), | |
| 704 | + this.formatMoney(item.StudyPeriodDeduction), | |
| 705 | + this.formatMoney(item.WorkClothesDeduction), | |
| 706 | + this.formatMoney(item.TotalDeduction), | |
| 707 | + this.formatMoney(item.Bonus), | |
| 708 | + this.formatMoney(item.ReturnPhoneDeposit), | |
| 709 | + this.formatMoney(item.ReturnAccommodationDeposit), | |
| 710 | + this.formatMoney(item.LastMonthSupplement), | |
| 711 | + this.formatMoney(item.ActualSalary), | |
| 712 | + item.MonthlyPaymentStatus || '无', | |
| 713 | + this.formatMoney(item.PaidAmount), | |
| 714 | + this.formatMoney(item.PendingAmount), | |
| 715 | + this.formatMoney(item.MonthlyTotalPayment), | |
| 716 | + item.IsLocked === 1 ? '已锁定' : '未锁定' | |
| 717 | + ]) | |
| 718 | + | |
| 719 | + // 合并表头和数据 | |
| 720 | + const excelData = [headers, ...dataRows] | |
| 721 | + | |
| 722 | + // 创建工作表 | |
| 723 | + const ws = XLSX.utils.aoa_to_sheet(excelData) | |
| 724 | + | |
| 725 | + // 设置列宽 | |
| 726 | + const colWidths = headers.map(() => ({ wch: 15 })) | |
| 727 | + ws['!cols'] = colWidths | |
| 728 | + | |
| 729 | + // 创建工作簿 | |
| 730 | + const wb = XLSX.utils.book_new() | |
| 731 | + XLSX.utils.book_append_sheet(wb, ws, '大项目主管工资') | |
| 732 | + | |
| 733 | + // 生成文件名 | |
| 734 | + const now = new Date() | |
| 735 | + const timestamp = now.getFullYear() + | |
| 736 | + String(now.getMonth() + 1).padStart(2, '0') + | |
| 737 | + String(now.getDate()).padStart(2, '0') + | |
| 738 | + String(now.getHours()).padStart(2, '0') + | |
| 739 | + String(now.getMinutes()).padStart(2, '0') + | |
| 740 | + String(now.getSeconds()).padStart(2, '0') | |
| 741 | + const fileName = `大项目主管工资_${timestamp}.xlsx` | |
| 742 | + | |
| 743 | + // 导出文件 | |
| 744 | + XLSX.writeFile(wb, fileName) | |
| 745 | + | |
| 746 | + this.$message.success('导出成功') | |
| 747 | + } catch (error) { | |
| 748 | + console.error('导出失败:', error) | |
| 749 | + this.$message.error('导出失败,请重试') | |
| 750 | + } finally { | |
| 751 | + this.exportLoading = false | |
| 752 | + } | |
| 753 | + }, | |
| 754 | + | |
| 578 | 755 | // 格式化金额 |
| 579 | 756 | formatMoney(value) { |
| 580 | 757 | if (value === null || value === undefined || value === '') { | ... | ... |
antis-ncc-admin/src/views/wageManagement/shop-stock-detail-dialog.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + title="门店股份详情" | |
| 4 | + :visible="visible" | |
| 5 | + width="1400px" | |
| 6 | + :close-on-click-modal="false" | |
| 7 | + @close="handleClose" | |
| 8 | + class="detail-dialog" | |
| 9 | + > | |
| 10 | + <div v-if="detailData" class="detail-content"> | |
| 11 | + <!-- 基本信息 --> | |
| 12 | + <div class="detail-section"> | |
| 13 | + <div class="section-title"> | |
| 14 | + <i class="el-icon-user"></i> | |
| 15 | + <span>基本信息</span> | |
| 16 | + </div> | |
| 17 | + <div class="section-content"> | |
| 18 | + <div class="info-row"> | |
| 19 | + <div class="info-item"> | |
| 20 | + <span class="label">门店名称:</span> | |
| 21 | + <span class="value">{{ detailData.StoreName || '无' }}</span> | |
| 22 | + </div> | |
| 23 | + <div class="info-item"> | |
| 24 | + <span class="label">统计月份:</span> | |
| 25 | + <span class="value">{{ formatMonth(detailData.StatisticsMonth) || '无' }}</span> | |
| 26 | + </div> | |
| 27 | + <div class="info-item" v-if="detailData.CreateTime"> | |
| 28 | + <span class="label">创建时间:</span> | |
| 29 | + <span class="value">{{ formatDateTime(detailData.CreateTime) }}</span> | |
| 30 | + </div> | |
| 31 | + <div class="info-item" v-if="detailData.UpdateTime"> | |
| 32 | + <span class="label">更新时间:</span> | |
| 33 | + <span class="value">{{ formatDateTime(detailData.UpdateTime) }}</span> | |
| 34 | + </div> | |
| 35 | + </div> | |
| 36 | + </div> | |
| 37 | + </div> | |
| 38 | + | |
| 39 | + <!-- 收入信息 --> | |
| 40 | + <div class="detail-section"> | |
| 41 | + <div class="section-title"> | |
| 42 | + <i class="el-icon-trophy"></i> | |
| 43 | + <span>收入信息</span> | |
| 44 | + </div> | |
| 45 | + <div class="section-content"> | |
| 46 | + <div class="info-row"> | |
| 47 | + <div class="info-item"> | |
| 48 | + <span class="label">主营收入:</span> | |
| 49 | + <span class="value highlight">{{ formatMoney(detailData.MainIncome) }}</span> | |
| 50 | + </div> | |
| 51 | + <div class="info-item"> | |
| 52 | + <span class="label">生美消耗业绩:</span> | |
| 53 | + <span class="value">{{ formatMoney(detailData.ConsumeLifeBeauty) }}</span> | |
| 54 | + </div> | |
| 55 | + <div class="info-item"> | |
| 56 | + <span class="label">科美消耗业绩:</span> | |
| 57 | + <span class="value">{{ formatMoney(detailData.ConsumeTechBeauty) }}</span> | |
| 58 | + </div> | |
| 59 | + <div class="info-item"> | |
| 60 | + <span class="label">医美消耗业绩:</span> | |
| 61 | + <span class="value">{{ formatMoney(detailData.ConsumeMedicalBeauty) }}</span> | |
| 62 | + </div> | |
| 63 | + <div class="info-item"> | |
| 64 | + <span class="label">合作消费业绩:</span> | |
| 65 | + <span class="value">{{ formatMoney(detailData.ConsumeCooperation) }}</span> | |
| 66 | + </div> | |
| 67 | + <div class="info-item"> | |
| 68 | + <span class="label">产品消耗业绩:</span> | |
| 69 | + <span class="value">{{ formatMoney(detailData.ConsumeProduct) }}</span> | |
| 70 | + </div> | |
| 71 | + <div class="info-item"> | |
| 72 | + <span class="label">其他消耗业绩:</span> | |
| 73 | + <span class="value">{{ formatMoney(detailData.ConsumeOther) }}</span> | |
| 74 | + </div> | |
| 75 | + <div class="info-item"> | |
| 76 | + <span class="label">其他收入:</span> | |
| 77 | + <span class="value">{{ formatMoney(detailData.OtherIncome) }}</span> | |
| 78 | + </div> | |
| 79 | + <div class="info-item"> | |
| 80 | + <span class="label">预收款:</span> | |
| 81 | + <span class="value">{{ formatMoney(detailData.AdvanceReceipt) }}</span> | |
| 82 | + </div> | |
| 83 | + <div class="info-item"> | |
| 84 | + <span class="label">实际退款:</span> | |
| 85 | + <span class="value">{{ formatMoney(detailData.Refund) }}</span> | |
| 86 | + </div> | |
| 87 | + <div class="info-item"> | |
| 88 | + <span class="label">应收:</span> | |
| 89 | + <span class="value">{{ formatMoney(detailData.Receivables) }}</span> | |
| 90 | + </div> | |
| 91 | + <div class="info-item"> | |
| 92 | + <span class="label">银行存款:</span> | |
| 93 | + <span class="value">{{ formatMoney(detailData.BankDeposit) }}</span> | |
| 94 | + </div> | |
| 95 | + </div> | |
| 96 | + </div> | |
| 97 | + </div> | |
| 98 | + | |
| 99 | + <!-- 成本信息 --> | |
| 100 | + <div class="detail-section"> | |
| 101 | + <div class="section-title"> | |
| 102 | + <i class="el-icon-shopping-cart-2"></i> | |
| 103 | + <span>成本信息</span> | |
| 104 | + </div> | |
| 105 | + <div class="section-content"> | |
| 106 | + <div class="info-row"> | |
| 107 | + <div class="info-item"> | |
| 108 | + <span class="label">主营成本-产品:</span> | |
| 109 | + <span class="value">{{ formatMoney(detailData.CostProduct) }}</span> | |
| 110 | + </div> | |
| 111 | + <div class="info-item"> | |
| 112 | + <span class="label">主营成本-福田:</span> | |
| 113 | + <span class="value">{{ formatMoney(detailData.CostFutian) }}</span> | |
| 114 | + </div> | |
| 115 | + <div class="info-item"> | |
| 116 | + <span class="label">主营成本-毛巾:</span> | |
| 117 | + <span class="value">{{ formatMoney(detailData.CostTowel) }}</span> | |
| 118 | + </div> | |
| 119 | + <div class="info-item"> | |
| 120 | + <span class="label">主营成本-科技部:</span> | |
| 121 | + <span class="value">{{ formatMoney(detailData.CostTechDept) }}</span> | |
| 122 | + </div> | |
| 123 | + <div class="info-item"> | |
| 124 | + <span class="label">主营成本-管理费:</span> | |
| 125 | + <span class="value">{{ formatMoney(detailData.CostManagementFee) }}</span> | |
| 126 | + </div> | |
| 127 | + <div class="info-item"> | |
| 128 | + <span class="label">主营成本-合作:</span> | |
| 129 | + <span class="value">{{ formatMoney(detailData.CostCooperation) }}</span> | |
| 130 | + </div> | |
| 131 | + <div class="info-item"> | |
| 132 | + <span class="label">主营成本-大项目:</span> | |
| 133 | + <span class="value">{{ formatMoney(detailData.CostMajorProject) }}</span> | |
| 134 | + </div> | |
| 135 | + <div class="info-item"> | |
| 136 | + <span class="label">其他成本:</span> | |
| 137 | + <span class="value">{{ formatMoney(detailData.CostOther) }}</span> | |
| 138 | + </div> | |
| 139 | + </div> | |
| 140 | + </div> | |
| 141 | + </div> | |
| 142 | + | |
| 143 | + <!-- 人工工资信息 --> | |
| 144 | + <div class="detail-section"> | |
| 145 | + <div class="section-title"> | |
| 146 | + <i class="el-icon-wallet"></i> | |
| 147 | + <span>人工工资信息</span> | |
| 148 | + </div> | |
| 149 | + <div class="section-content"> | |
| 150 | + <div class="info-row"> | |
| 151 | + <div class="info-item"> | |
| 152 | + <span class="label">健康师底薪:</span> | |
| 153 | + <span class="value">{{ formatMoney(detailData.SalaryBaseHealthCoach) }}</span> | |
| 154 | + </div> | |
| 155 | + <div class="info-item"> | |
| 156 | + <span class="label">店助底薪:</span> | |
| 157 | + <span class="value">{{ formatMoney(detailData.SalaryBaseAssistant) }}</span> | |
| 158 | + </div> | |
| 159 | + <div class="info-item"> | |
| 160 | + <span class="label">店助主任底薪:</span> | |
| 161 | + <span class="value">{{ formatMoney(detailData.SalaryBaseDirector) }}</span> | |
| 162 | + </div> | |
| 163 | + <div class="info-item"> | |
| 164 | + <span class="label">店长底薪:</span> | |
| 165 | + <span class="value">{{ formatMoney(detailData.SalaryBaseStoreManager) }}</span> | |
| 166 | + </div> | |
| 167 | + <div class="info-item"> | |
| 168 | + <span class="label">总经理/经理底薪:</span> | |
| 169 | + <span class="value">{{ formatMoney(detailData.SalaryBaseGeneralManager) }}</span> | |
| 170 | + </div> | |
| 171 | + <div class="info-item"> | |
| 172 | + <span class="label">健康师提成:</span> | |
| 173 | + <span class="value">{{ formatMoney(detailData.SalaryCommissionHealthCoach) }}</span> | |
| 174 | + </div> | |
| 175 | + <div class="info-item"> | |
| 176 | + <span class="label">店助提成:</span> | |
| 177 | + <span class="value">{{ formatMoney(detailData.SalaryCommissionAssistant) }}</span> | |
| 178 | + </div> | |
| 179 | + <div class="info-item"> | |
| 180 | + <span class="label">店助主任提成:</span> | |
| 181 | + <span class="value">{{ formatMoney(detailData.SalaryCommissionDirector) }}</span> | |
| 182 | + </div> | |
| 183 | + <div class="info-item"> | |
| 184 | + <span class="label">店长提成:</span> | |
| 185 | + <span class="value">{{ formatMoney(detailData.SalaryCommissionStoreManager) }}</span> | |
| 186 | + </div> | |
| 187 | + <div class="info-item"> | |
| 188 | + <span class="label">总经理/经理提成:</span> | |
| 189 | + <span class="value">{{ formatMoney(detailData.SalaryCommissionGeneralManager) }}</span> | |
| 190 | + </div> | |
| 191 | + <div class="info-item"> | |
| 192 | + <span class="label">手工:</span> | |
| 193 | + <span class="value">{{ formatMoney(detailData.SalaryManual) }}</span> | |
| 194 | + </div> | |
| 195 | + <div class="info-item"> | |
| 196 | + <span class="label">出勤:</span> | |
| 197 | + <span class="value">{{ formatMoney(detailData.SalaryAttendance) }}</span> | |
| 198 | + </div> | |
| 199 | + <div class="info-item"> | |
| 200 | + <span class="label">手机保管费:</span> | |
| 201 | + <span class="value">{{ formatMoney(detailData.SalaryPhoneCustody) }}</span> | |
| 202 | + </div> | |
| 203 | + <div class="info-item"> | |
| 204 | + <span class="label">人头:</span> | |
| 205 | + <span class="value">{{ formatMoney(detailData.SalaryHeadcountReward) }}</span> | |
| 206 | + </div> | |
| 207 | + <div class="info-item"> | |
| 208 | + <span class="label">门店T区:</span> | |
| 209 | + <span class="value">{{ formatMoney(detailData.SalaryTZone) }}</span> | |
| 210 | + </div> | |
| 211 | + </div> | |
| 212 | + </div> | |
| 213 | + </div> | |
| 214 | + | |
| 215 | + <!-- 费用与其他 --> | |
| 216 | + <div class="detail-section"> | |
| 217 | + <div class="section-title"> | |
| 218 | + <i class="el-icon-money"></i> | |
| 219 | + <span>费用与其他</span> | |
| 220 | + </div> | |
| 221 | + <div class="section-content"> | |
| 222 | + <div class="info-row"> | |
| 223 | + <div class="info-item"> | |
| 224 | + <span class="label">社保:</span> | |
| 225 | + <span class="value">{{ formatMoney(detailData.SocialSecurity) }}</span> | |
| 226 | + </div> | |
| 227 | + <div class="info-item"> | |
| 228 | + <span class="label">门店房租:</span> | |
| 229 | + <span class="value">{{ formatMoney(detailData.StoreRent) }}</span> | |
| 230 | + </div> | |
| 231 | + <div class="info-item"> | |
| 232 | + <span class="label">宿舍房租:</span> | |
| 233 | + <span class="value">{{ formatMoney(detailData.DormRent) }}</span> | |
| 234 | + </div> | |
| 235 | + <div class="info-item"> | |
| 236 | + <span class="label">当期费用:</span> | |
| 237 | + <span class="value">{{ formatMoney(detailData.CurrentPeriodExpense) }}</span> | |
| 238 | + </div> | |
| 239 | + <div class="info-item"> | |
| 240 | + <span class="label">当前费用-秦董:</span> | |
| 241 | + <span class="value">{{ formatMoney(detailData.CurrentPeriodExpenseQin) }}</span> | |
| 242 | + </div> | |
| 243 | + <div class="info-item"> | |
| 244 | + <span class="label">财务费用:</span> | |
| 245 | + <span class="value">{{ formatMoney(detailData.FinancialFee) }}</span> | |
| 246 | + </div> | |
| 247 | + </div> | |
| 248 | + </div> | |
| 249 | + </div> | |
| 250 | + | |
| 251 | + <!-- 奖励 --> | |
| 252 | + <div class="detail-section"> | |
| 253 | + <div class="section-title"> | |
| 254 | + <i class="el-icon-medal"></i> | |
| 255 | + <span>奖励</span> | |
| 256 | + </div> | |
| 257 | + <div class="section-content"> | |
| 258 | + <div class="info-row"> | |
| 259 | + <div class="info-item"> | |
| 260 | + <span class="label">奖励-医美:</span> | |
| 261 | + <span class="value">{{ formatMoney(detailData.RewardMedicalBeauty) }}</span> | |
| 262 | + </div> | |
| 263 | + <div class="info-item"> | |
| 264 | + <span class="label">奖励-其他:</span> | |
| 265 | + <span class="value">{{ formatMoney(detailData.RewardOther) }}</span> | |
| 266 | + </div> | |
| 267 | + <div class="info-item"> | |
| 268 | + <span class="label">奖励-大单奖:</span> | |
| 269 | + <span class="value">{{ formatMoney(detailData.RewardLargeOrder) }}</span> | |
| 270 | + </div> | |
| 271 | + <div class="info-item"> | |
| 272 | + <span class="label">奖励-首单奖:</span> | |
| 273 | + <span class="value">{{ formatMoney(detailData.RewardFirstOrder) }}</span> | |
| 274 | + </div> | |
| 275 | + <div class="info-item"> | |
| 276 | + <span class="label">奖励:</span> | |
| 277 | + <span class="value">{{ formatMoney(detailData.RewardGeneral) }}</span> | |
| 278 | + </div> | |
| 279 | + </div> | |
| 280 | + </div> | |
| 281 | + </div> | |
| 282 | + | |
| 283 | + <!-- 其他保留字段 --> | |
| 284 | + <div class="detail-section"> | |
| 285 | + <div class="section-title"> | |
| 286 | + <i class="el-icon-document"></i> | |
| 287 | + <span>其他</span> | |
| 288 | + </div> | |
| 289 | + <div class="section-content"> | |
| 290 | + <div class="info-row"> | |
| 291 | + <div class="info-item"> | |
| 292 | + <span class="label">其他1:</span> | |
| 293 | + <span class="value">{{ formatMoney(detailData.Other1) }}</span> | |
| 294 | + </div> | |
| 295 | + <div class="info-item"> | |
| 296 | + <span class="label">其他2:</span> | |
| 297 | + <span class="value">{{ formatMoney(detailData.Other2) }}</span> | |
| 298 | + </div> | |
| 299 | + </div> | |
| 300 | + </div> | |
| 301 | + </div> | |
| 302 | + | |
| 303 | + <!-- 利润结果 --> | |
| 304 | + <div class="detail-section"> | |
| 305 | + <div class="section-title"> | |
| 306 | + <i class="el-icon-data-line"></i> | |
| 307 | + <span>利润结果</span> | |
| 308 | + </div> | |
| 309 | + <div class="section-content"> | |
| 310 | + <div class="info-row"> | |
| 311 | + <div class="info-item"> | |
| 312 | + <span class="label">利润:</span> | |
| 313 | + <span class="value highlight large">{{ formatMoney(detailData.Profit) }}</span> | |
| 314 | + </div> | |
| 315 | + <div class="info-item"> | |
| 316 | + <span class="label">财务利润:</span> | |
| 317 | + <span class="value highlight large">{{ formatMoney(detailData.FinancialProfit) }}</span> | |
| 318 | + </div> | |
| 319 | + </div> | |
| 320 | + </div> | |
| 321 | + </div> | |
| 322 | + </div> | |
| 323 | + <div slot="footer" class="dialog-footer"> | |
| 324 | + <el-button @click="handleClose">关闭</el-button> | |
| 325 | + </div> | |
| 326 | + </el-dialog> | |
| 327 | +</template> | |
| 328 | + | |
| 329 | +<script> | |
| 330 | +export default { | |
| 331 | + name: 'ShopStockDetailDialog', | |
| 332 | + props: { | |
| 333 | + visible: { | |
| 334 | + type: Boolean, | |
| 335 | + default: false | |
| 336 | + }, | |
| 337 | + detailData: { | |
| 338 | + type: Object, | |
| 339 | + default: null | |
| 340 | + } | |
| 341 | + }, | |
| 342 | + methods: { | |
| 343 | + handleClose() { | |
| 344 | + this.$emit('close') | |
| 345 | + }, | |
| 346 | + formatMoney(value) { | |
| 347 | + if (value === null || value === undefined || value === '') { | |
| 348 | + return '0.00' | |
| 349 | + } | |
| 350 | + return Number(value).toFixed(2) | |
| 351 | + }, | |
| 352 | + formatMonth(value) { | |
| 353 | + if (!value || value.length !== 6) { | |
| 354 | + return value || '无' | |
| 355 | + } | |
| 356 | + const year = value.substring(0, 4) | |
| 357 | + const month = value.substring(4, 6) | |
| 358 | + return `${year}-${month}` | |
| 359 | + }, | |
| 360 | + formatDateTime(value) { | |
| 361 | + if (!value) return '无' | |
| 362 | + const date = new Date(value) | |
| 363 | + const year = date.getFullYear() | |
| 364 | + const month = String(date.getMonth() + 1).padStart(2, '0') | |
| 365 | + const day = String(date.getDate()).padStart(2, '0') | |
| 366 | + const hours = String(date.getHours()).padStart(2, '0') | |
| 367 | + const minutes = String(date.getMinutes()).padStart(2, '0') | |
| 368 | + const seconds = String(date.getSeconds()).padStart(2, '0') | |
| 369 | + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` | |
| 370 | + } | |
| 371 | + } | |
| 372 | +} | |
| 373 | +</script> | |
| 374 | + | |
| 375 | +<style lang="scss" scoped> | |
| 376 | +.detail-dialog { | |
| 377 | + .detail-content { | |
| 378 | + max-height: 70vh; | |
| 379 | + overflow-y: auto; | |
| 380 | + padding: 20px; | |
| 381 | + } | |
| 382 | + | |
| 383 | + .detail-section { | |
| 384 | + margin-bottom: 24px; | |
| 385 | + background: #f9f9f9; | |
| 386 | + border-radius: 8px; | |
| 387 | + padding: 16px; | |
| 388 | + | |
| 389 | + &:last-child { | |
| 390 | + margin-bottom: 0; | |
| 391 | + } | |
| 392 | + | |
| 393 | + .section-title { | |
| 394 | + display: flex; | |
| 395 | + align-items: center; | |
| 396 | + gap: 8px; | |
| 397 | + margin-bottom: 16px; | |
| 398 | + font-size: 16px; | |
| 399 | + font-weight: 600; | |
| 400 | + color: #303133; | |
| 401 | + border-bottom: 2px solid #409EFF; | |
| 402 | + padding-bottom: 8px; | |
| 403 | + | |
| 404 | + i { | |
| 405 | + color: #409EFF; | |
| 406 | + font-size: 18px; | |
| 407 | + } | |
| 408 | + } | |
| 409 | + | |
| 410 | + .section-content { | |
| 411 | + .info-row { | |
| 412 | + display: flex; | |
| 413 | + flex-wrap: wrap; | |
| 414 | + gap: 20px; | |
| 415 | + | |
| 416 | + .info-item { | |
| 417 | + flex: 0 0 calc(25% - 15px); | |
| 418 | + min-width: 200px; | |
| 419 | + display: flex; | |
| 420 | + align-items: center; | |
| 421 | + padding: 8px 12px; | |
| 422 | + background: #fff; | |
| 423 | + border-radius: 4px; | |
| 424 | + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); | |
| 425 | + | |
| 426 | + .label { | |
| 427 | + color: #606266; | |
| 428 | + font-weight: 500; | |
| 429 | + margin-right: 8px; | |
| 430 | + white-space: nowrap; | |
| 431 | + } | |
| 432 | + | |
| 433 | + .value { | |
| 434 | + color: #303133; | |
| 435 | + flex: 1; | |
| 436 | + text-align: right; | |
| 437 | + | |
| 438 | + &.highlight { | |
| 439 | + color: #409EFF; | |
| 440 | + font-weight: 600; | |
| 441 | + } | |
| 442 | + | |
| 443 | + &.large { | |
| 444 | + font-size: 18px; | |
| 445 | + } | |
| 446 | + } | |
| 447 | + } | |
| 448 | + } | |
| 449 | + } | |
| 450 | + } | |
| 451 | + | |
| 452 | + .dialog-footer { | |
| 453 | + text-align: right; | |
| 454 | + padding: 20px; | |
| 455 | + border-top: 1px solid #e4e7ed; | |
| 456 | + } | |
| 457 | +} | |
| 458 | + | |
| 459 | +// 滚动条样式 | |
| 460 | +.detail-content::-webkit-scrollbar { | |
| 461 | + width: 6px; | |
| 462 | +} | |
| 463 | + | |
| 464 | +.detail-content::-webkit-scrollbar-track { | |
| 465 | + background: #f1f1f1; | |
| 466 | + border-radius: 3px; | |
| 467 | +} | |
| 468 | + | |
| 469 | +.detail-content::-webkit-scrollbar-thumb { | |
| 470 | + background: #c1c1c1; | |
| 471 | + border-radius: 3px; | |
| 472 | + | |
| 473 | + &:hover { | |
| 474 | + background: #a8a8a8; | |
| 475 | + } | |
| 476 | +} | |
| 477 | +</style> | |
| 478 | + | ... | ... |
antis-ncc-admin/src/views/wageManagement/shop-stock.vue
| ... | ... | @@ -8,8 +8,24 @@ |
| 8 | 8 | </div> |
| 9 | 9 | <div class="header-right"> |
| 10 | 10 | <el-button |
| 11 | + type="success" | |
| 12 | + icon="el-icon-download" | |
| 13 | + @click="handleExport" | |
| 14 | + :loading="exportLoading" | |
| 15 | + > | |
| 16 | + 导出 | |
| 17 | + </el-button> | |
| 18 | + <el-button | |
| 19 | + type="primary" | |
| 20 | + icon="el-icon-cpu" | |
| 21 | + @click="showCalculateDialog" | |
| 22 | + :loading="calculateLoading" | |
| 23 | + > | |
| 24 | + 计算股份 | |
| 25 | + </el-button> | |
| 26 | + <el-button | |
| 11 | 27 | icon="el-icon-refresh" |
| 12 | - @click="handleRefresh" | |
| 28 | + @click="getList" | |
| 13 | 29 | :loading="loading" |
| 14 | 30 | > |
| 15 | 31 | 刷新 |
| ... | ... | @@ -17,28 +33,754 @@ |
| 17 | 33 | </div> |
| 18 | 34 | </div> |
| 19 | 35 | |
| 20 | - <!-- 内容区域 --> | |
| 21 | - <div class="content-container"> | |
| 22 | - <!-- 待开发 --> | |
| 36 | + <!-- 搜索区域 --> | |
| 37 | + <div class="search-container"> | |
| 38 | + <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="80px"> | |
| 39 | + <el-form-item label="统计月份" prop="statisticsMonth"> | |
| 40 | + <el-date-picker | |
| 41 | + v-model="queryParams.statisticsMonth" | |
| 42 | + type="month" | |
| 43 | + placeholder="选择月份" | |
| 44 | + format="yyyyMM" | |
| 45 | + value-format="yyyyMM" | |
| 46 | + style="width: 200px" | |
| 47 | + /> | |
| 48 | + </el-form-item> | |
| 49 | + <el-form-item label="门店" prop="storeId"> | |
| 50 | + <el-select | |
| 51 | + v-model="queryParams.storeId" | |
| 52 | + placeholder="请选择门店" | |
| 53 | + clearable | |
| 54 | + filterable | |
| 55 | + style="width: 200px" | |
| 56 | + > | |
| 57 | + <el-option | |
| 58 | + v-for="store in storeOptions" | |
| 59 | + :key="store.value" | |
| 60 | + :label="store.label" | |
| 61 | + :value="store.value" | |
| 62 | + /> | |
| 63 | + </el-select> | |
| 64 | + </el-form-item> | |
| 65 | + <el-form-item> | |
| 66 | + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> | |
| 67 | + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button> | |
| 68 | + </el-form-item> | |
| 69 | + </el-form> | |
| 23 | 70 | </div> |
| 71 | + | |
| 72 | + <!-- 数据表格 --> | |
| 73 | + <div class="table-container"> | |
| 74 | + <NCC-table | |
| 75 | + v-loading="loading" | |
| 76 | + :data="list" | |
| 77 | + border | |
| 78 | + stripe | |
| 79 | + height="calc(100vh - 420px)" | |
| 80 | + :header-cell-style="{ background: '#f5f7fa', color: '#606266' }" | |
| 81 | + > | |
| 82 | + <!-- 基本信息 --> | |
| 83 | + <el-table-column prop="StoreName" label="门店名称" width="150" align="center" fixed="left"> | |
| 84 | + <template slot-scope="scope"> | |
| 85 | + <div class="store-name"> | |
| 86 | + <i class="el-icon-shop store-icon"></i> | |
| 87 | + <span>{{ scope.row.StoreName || '无' }}</span> | |
| 88 | + </div> | |
| 89 | + </template> | |
| 90 | + </el-table-column> | |
| 91 | + <el-table-column prop="StatisticsMonth" label="统计月份" width="120" align="center" fixed="left"> | |
| 92 | + <template slot-scope="scope"> | |
| 93 | + <span>{{ formatMonth(scope.row.StatisticsMonth) || '无' }}</span> | |
| 94 | + </template> | |
| 95 | + </el-table-column> | |
| 96 | + | |
| 97 | + <!-- 收入部分 --> | |
| 98 | + <el-table-column label="收入信息" align="center"> | |
| 99 | + <el-table-column prop="MainIncome" label="主营收入" width="120" align="center"> | |
| 100 | + <template slot-scope="scope"> | |
| 101 | + <span>{{ formatMoney(scope.row.MainIncome) }}</span> | |
| 102 | + </template> | |
| 103 | + </el-table-column> | |
| 104 | + <el-table-column prop="ConsumeLifeBeauty" label="生美消耗业绩" width="140" align="center"> | |
| 105 | + <template slot-scope="scope"> | |
| 106 | + <span>{{ formatMoney(scope.row.ConsumeLifeBeauty) }}</span> | |
| 107 | + </template> | |
| 108 | + </el-table-column> | |
| 109 | + <el-table-column prop="ConsumeTechBeauty" label="科美消耗业绩" width="140" align="center"> | |
| 110 | + <template slot-scope="scope"> | |
| 111 | + <span>{{ formatMoney(scope.row.ConsumeTechBeauty) }}</span> | |
| 112 | + </template> | |
| 113 | + </el-table-column> | |
| 114 | + <el-table-column prop="ConsumeMedicalBeauty" label="医美消耗业绩" width="140" align="center"> | |
| 115 | + <template slot-scope="scope"> | |
| 116 | + <span>{{ formatMoney(scope.row.ConsumeMedicalBeauty) }}</span> | |
| 117 | + </template> | |
| 118 | + </el-table-column> | |
| 119 | + <el-table-column prop="ConsumeCooperation" label="合作消费业绩" width="140" align="center"> | |
| 120 | + <template slot-scope="scope"> | |
| 121 | + <span>{{ formatMoney(scope.row.ConsumeCooperation) }}</span> | |
| 122 | + </template> | |
| 123 | + </el-table-column> | |
| 124 | + <el-table-column prop="ConsumeProduct" label="产品消耗业绩" width="140" align="center"> | |
| 125 | + <template slot-scope="scope"> | |
| 126 | + <span>{{ formatMoney(scope.row.ConsumeProduct) }}</span> | |
| 127 | + </template> | |
| 128 | + </el-table-column> | |
| 129 | + <el-table-column prop="ConsumeOther" label="其他消耗业绩" width="140" align="center"> | |
| 130 | + <template slot-scope="scope"> | |
| 131 | + <span>{{ formatMoney(scope.row.ConsumeOther) }}</span> | |
| 132 | + </template> | |
| 133 | + </el-table-column> | |
| 134 | + <el-table-column prop="OtherIncome" label="其他收入" width="120" align="center"> | |
| 135 | + <template slot-scope="scope"> | |
| 136 | + <span>{{ formatMoney(scope.row.OtherIncome) }}</span> | |
| 137 | + </template> | |
| 138 | + </el-table-column> | |
| 139 | + <el-table-column prop="AdvanceReceipt" label="预收款" width="120" align="center"> | |
| 140 | + <template slot-scope="scope"> | |
| 141 | + <span>{{ formatMoney(scope.row.AdvanceReceipt) }}</span> | |
| 142 | + </template> | |
| 143 | + </el-table-column> | |
| 144 | + <el-table-column prop="Refund" label="实际退款" width="120" align="center"> | |
| 145 | + <template slot-scope="scope"> | |
| 146 | + <span>{{ formatMoney(scope.row.Refund) }}</span> | |
| 147 | + </template> | |
| 148 | + </el-table-column> | |
| 149 | + <el-table-column prop="Receivables" label="应收" width="120" align="center"> | |
| 150 | + <template slot-scope="scope"> | |
| 151 | + <span>{{ formatMoney(scope.row.Receivables) }}</span> | |
| 152 | + </template> | |
| 153 | + </el-table-column> | |
| 154 | + <el-table-column prop="BankDeposit" label="银行存款" width="120" align="center"> | |
| 155 | + <template slot-scope="scope"> | |
| 156 | + <span>{{ formatMoney(scope.row.BankDeposit) }}</span> | |
| 157 | + </template> | |
| 158 | + </el-table-column> | |
| 159 | + </el-table-column> | |
| 160 | + | |
| 161 | + <!-- 成本部分 --> | |
| 162 | + <el-table-column label="成本信息" align="center"> | |
| 163 | + <el-table-column prop="CostProduct" label="主营成本-产品" width="140" align="center"> | |
| 164 | + <template slot-scope="scope"> | |
| 165 | + <span>{{ formatMoney(scope.row.CostProduct) }}</span> | |
| 166 | + </template> | |
| 167 | + </el-table-column> | |
| 168 | + <el-table-column prop="CostFutian" label="主营成本-福田" width="140" align="center"> | |
| 169 | + <template slot-scope="scope"> | |
| 170 | + <span>{{ formatMoney(scope.row.CostFutian) }}</span> | |
| 171 | + </template> | |
| 172 | + </el-table-column> | |
| 173 | + <el-table-column prop="CostTowel" label="主营成本-毛巾" width="140" align="center"> | |
| 174 | + <template slot-scope="scope"> | |
| 175 | + <span>{{ formatMoney(scope.row.CostTowel) }}</span> | |
| 176 | + </template> | |
| 177 | + </el-table-column> | |
| 178 | + <el-table-column prop="CostTechDept" label="主营成本-科技部" width="150" align="center"> | |
| 179 | + <template slot-scope="scope"> | |
| 180 | + <span>{{ formatMoney(scope.row.CostTechDept) }}</span> | |
| 181 | + </template> | |
| 182 | + </el-table-column> | |
| 183 | + <el-table-column prop="CostManagementFee" label="主营成本-管理费" width="150" align="center"> | |
| 184 | + <template slot-scope="scope"> | |
| 185 | + <span>{{ formatMoney(scope.row.CostManagementFee) }}</span> | |
| 186 | + </template> | |
| 187 | + </el-table-column> | |
| 188 | + <el-table-column prop="CostCooperation" label="主营成本-合作" width="140" align="center"> | |
| 189 | + <template slot-scope="scope"> | |
| 190 | + <span>{{ formatMoney(scope.row.CostCooperation) }}</span> | |
| 191 | + </template> | |
| 192 | + </el-table-column> | |
| 193 | + <el-table-column prop="CostMajorProject" label="主营成本-大项目" width="150" align="center"> | |
| 194 | + <template slot-scope="scope"> | |
| 195 | + <span>{{ formatMoney(scope.row.CostMajorProject) }}</span> | |
| 196 | + </template> | |
| 197 | + </el-table-column> | |
| 198 | + <el-table-column prop="CostOther" label="其他成本" width="120" align="center"> | |
| 199 | + <template slot-scope="scope"> | |
| 200 | + <span>{{ formatMoney(scope.row.CostOther) }}</span> | |
| 201 | + </template> | |
| 202 | + </el-table-column> | |
| 203 | + </el-table-column> | |
| 204 | + | |
| 205 | + <!-- 人工工资部分 --> | |
| 206 | + <el-table-column label="人工工资信息" align="center"> | |
| 207 | + <el-table-column prop="SalaryBaseHealthCoach" label="健康师底薪" width="120" align="center"> | |
| 208 | + <template slot-scope="scope"> | |
| 209 | + <span>{{ formatMoney(scope.row.SalaryBaseHealthCoach) }}</span> | |
| 210 | + </template> | |
| 211 | + </el-table-column> | |
| 212 | + <el-table-column prop="SalaryBaseAssistant" label="店助底薪" width="120" align="center"> | |
| 213 | + <template slot-scope="scope"> | |
| 214 | + <span>{{ formatMoney(scope.row.SalaryBaseAssistant) }}</span> | |
| 215 | + </template> | |
| 216 | + </el-table-column> | |
| 217 | + <el-table-column prop="SalaryBaseDirector" label="店助主任底薪" width="140" align="center"> | |
| 218 | + <template slot-scope="scope"> | |
| 219 | + <span>{{ formatMoney(scope.row.SalaryBaseDirector) }}</span> | |
| 220 | + </template> | |
| 221 | + </el-table-column> | |
| 222 | + <el-table-column prop="SalaryBaseStoreManager" label="店长底薪" width="120" align="center"> | |
| 223 | + <template slot-scope="scope"> | |
| 224 | + <span>{{ formatMoney(scope.row.SalaryBaseStoreManager) }}</span> | |
| 225 | + </template> | |
| 226 | + </el-table-column> | |
| 227 | + <el-table-column prop="SalaryBaseGeneralManager" label="总经理/经理底薪" width="160" align="center"> | |
| 228 | + <template slot-scope="scope"> | |
| 229 | + <span>{{ formatMoney(scope.row.SalaryBaseGeneralManager) }}</span> | |
| 230 | + </template> | |
| 231 | + </el-table-column> | |
| 232 | + <el-table-column prop="SalaryCommissionHealthCoach" label="健康师提成" width="120" align="center"> | |
| 233 | + <template slot-scope="scope"> | |
| 234 | + <span>{{ formatMoney(scope.row.SalaryCommissionHealthCoach) }}</span> | |
| 235 | + </template> | |
| 236 | + </el-table-column> | |
| 237 | + <el-table-column prop="SalaryCommissionAssistant" label="店助提成" width="120" align="center"> | |
| 238 | + <template slot-scope="scope"> | |
| 239 | + <span>{{ formatMoney(scope.row.SalaryCommissionAssistant) }}</span> | |
| 240 | + </template> | |
| 241 | + </el-table-column> | |
| 242 | + <el-table-column prop="SalaryCommissionDirector" label="店助主任提成" width="140" align="center"> | |
| 243 | + <template slot-scope="scope"> | |
| 244 | + <span>{{ formatMoney(scope.row.SalaryCommissionDirector) }}</span> | |
| 245 | + </template> | |
| 246 | + </el-table-column> | |
| 247 | + <el-table-column prop="SalaryCommissionStoreManager" label="店长提成" width="120" align="center"> | |
| 248 | + <template slot-scope="scope"> | |
| 249 | + <span>{{ formatMoney(scope.row.SalaryCommissionStoreManager) }}</span> | |
| 250 | + </template> | |
| 251 | + </el-table-column> | |
| 252 | + <el-table-column prop="SalaryCommissionGeneralManager" label="总经理/经理提成" width="160" align="center"> | |
| 253 | + <template slot-scope="scope"> | |
| 254 | + <span>{{ formatMoney(scope.row.SalaryCommissionGeneralManager) }}</span> | |
| 255 | + </template> | |
| 256 | + </el-table-column> | |
| 257 | + <el-table-column prop="SalaryManual" label="手工" width="100" align="center"> | |
| 258 | + <template slot-scope="scope"> | |
| 259 | + <span>{{ formatMoney(scope.row.SalaryManual) }}</span> | |
| 260 | + </template> | |
| 261 | + </el-table-column> | |
| 262 | + <el-table-column prop="SalaryAttendance" label="出勤" width="100" align="center"> | |
| 263 | + <template slot-scope="scope"> | |
| 264 | + <span>{{ formatMoney(scope.row.SalaryAttendance) }}</span> | |
| 265 | + </template> | |
| 266 | + </el-table-column> | |
| 267 | + <el-table-column prop="SalaryPhoneCustody" label="手机保管费" width="120" align="center"> | |
| 268 | + <template slot-scope="scope"> | |
| 269 | + <span>{{ formatMoney(scope.row.SalaryPhoneCustody) }}</span> | |
| 270 | + </template> | |
| 271 | + </el-table-column> | |
| 272 | + <el-table-column prop="SalaryHeadcountReward" label="人头" width="100" align="center"> | |
| 273 | + <template slot-scope="scope"> | |
| 274 | + <span>{{ formatMoney(scope.row.SalaryHeadcountReward) }}</span> | |
| 275 | + </template> | |
| 276 | + </el-table-column> | |
| 277 | + <el-table-column prop="SalaryTZone" label="门店T区" width="120" align="center"> | |
| 278 | + <template slot-scope="scope"> | |
| 279 | + <span>{{ formatMoney(scope.row.SalaryTZone) }}</span> | |
| 280 | + </template> | |
| 281 | + </el-table-column> | |
| 282 | + </el-table-column> | |
| 283 | + | |
| 284 | + <!-- 费用与其他 --> | |
| 285 | + <el-table-column label="费用与其他" align="center"> | |
| 286 | + <el-table-column prop="SocialSecurity" label="社保" width="100" align="center"> | |
| 287 | + <template slot-scope="scope"> | |
| 288 | + <span>{{ formatMoney(scope.row.SocialSecurity) }}</span> | |
| 289 | + </template> | |
| 290 | + </el-table-column> | |
| 291 | + <el-table-column prop="StoreRent" label="门店房租" width="120" align="center"> | |
| 292 | + <template slot-scope="scope"> | |
| 293 | + <span>{{ formatMoney(scope.row.StoreRent) }}</span> | |
| 294 | + </template> | |
| 295 | + </el-table-column> | |
| 296 | + <el-table-column prop="DormRent" label="宿舍房租" width="120" align="center"> | |
| 297 | + <template slot-scope="scope"> | |
| 298 | + <span>{{ formatMoney(scope.row.DormRent) }}</span> | |
| 299 | + </template> | |
| 300 | + </el-table-column> | |
| 301 | + <el-table-column prop="CurrentPeriodExpense" label="当期费用" width="120" align="center"> | |
| 302 | + <template slot-scope="scope"> | |
| 303 | + <span>{{ formatMoney(scope.row.CurrentPeriodExpense) }}</span> | |
| 304 | + </template> | |
| 305 | + </el-table-column> | |
| 306 | + <el-table-column prop="CurrentPeriodExpenseQin" label="当前费用-秦董" width="140" align="center"> | |
| 307 | + <template slot-scope="scope"> | |
| 308 | + <span>{{ formatMoney(scope.row.CurrentPeriodExpenseQin) }}</span> | |
| 309 | + </template> | |
| 310 | + </el-table-column> | |
| 311 | + <el-table-column prop="FinancialFee" label="财务费用" width="120" align="center"> | |
| 312 | + <template slot-scope="scope"> | |
| 313 | + <span>{{ formatMoney(scope.row.FinancialFee) }}</span> | |
| 314 | + </template> | |
| 315 | + </el-table-column> | |
| 316 | + </el-table-column> | |
| 317 | + | |
| 318 | + <!-- 奖励 --> | |
| 319 | + <el-table-column label="奖励" align="center"> | |
| 320 | + <el-table-column prop="RewardMedicalBeauty" label="奖励-医美" width="120" align="center"> | |
| 321 | + <template slot-scope="scope"> | |
| 322 | + <span>{{ formatMoney(scope.row.RewardMedicalBeauty) }}</span> | |
| 323 | + </template> | |
| 324 | + </el-table-column> | |
| 325 | + <el-table-column prop="RewardOther" label="奖励-其他" width="120" align="center"> | |
| 326 | + <template slot-scope="scope"> | |
| 327 | + <span>{{ formatMoney(scope.row.RewardOther) }}</span> | |
| 328 | + </template> | |
| 329 | + </el-table-column> | |
| 330 | + <el-table-column prop="RewardLargeOrder" label="奖励-大单奖" width="130" align="center"> | |
| 331 | + <template slot-scope="scope"> | |
| 332 | + <span>{{ formatMoney(scope.row.RewardLargeOrder) }}</span> | |
| 333 | + </template> | |
| 334 | + </el-table-column> | |
| 335 | + <el-table-column prop="RewardFirstOrder" label="奖励-首单奖" width="130" align="center"> | |
| 336 | + <template slot-scope="scope"> | |
| 337 | + <span>{{ formatMoney(scope.row.RewardFirstOrder) }}</span> | |
| 338 | + </template> | |
| 339 | + </el-table-column> | |
| 340 | + <el-table-column prop="RewardGeneral" label="奖励" width="100" align="center"> | |
| 341 | + <template slot-scope="scope"> | |
| 342 | + <span>{{ formatMoney(scope.row.RewardGeneral) }}</span> | |
| 343 | + </template> | |
| 344 | + </el-table-column> | |
| 345 | + </el-table-column> | |
| 346 | + | |
| 347 | + <!-- 其他保留字段 --> | |
| 348 | + <el-table-column label="其他" align="center"> | |
| 349 | + <el-table-column prop="Other1" label="其他1" width="100" align="center"> | |
| 350 | + <template slot-scope="scope"> | |
| 351 | + <span>{{ formatMoney(scope.row.Other1) }}</span> | |
| 352 | + </template> | |
| 353 | + </el-table-column> | |
| 354 | + <el-table-column prop="Other2" label="其他2" width="100" align="center"> | |
| 355 | + <template slot-scope="scope"> | |
| 356 | + <span>{{ formatMoney(scope.row.Other2) }}</span> | |
| 357 | + </template> | |
| 358 | + </el-table-column> | |
| 359 | + </el-table-column> | |
| 360 | + | |
| 361 | + <!-- 利润结果 --> | |
| 362 | + <el-table-column label="利润结果" align="center"> | |
| 363 | + <el-table-column prop="Profit" label="利润" width="120" align="center"> | |
| 364 | + <template slot-scope="scope"> | |
| 365 | + <span class="highlight">{{ formatMoney(scope.row.Profit) }}</span> | |
| 366 | + </template> | |
| 367 | + </el-table-column> | |
| 368 | + <el-table-column prop="FinancialProfit" label="财务利润" width="120" align="center"> | |
| 369 | + <template slot-scope="scope"> | |
| 370 | + <span class="highlight">{{ formatMoney(scope.row.FinancialProfit) }}</span> | |
| 371 | + </template> | |
| 372 | + </el-table-column> | |
| 373 | + </el-table-column> | |
| 374 | + | |
| 375 | + <!-- 操作列 --> | |
| 376 | + <el-table-column label="操作" width="120" align="center" fixed="right"> | |
| 377 | + <template slot-scope="scope"> | |
| 378 | + <el-button | |
| 379 | + type="text" | |
| 380 | + size="mini" | |
| 381 | + icon="el-icon-view" | |
| 382 | + @click="showDetail(scope.row)" | |
| 383 | + > | |
| 384 | + 查看详情 | |
| 385 | + </el-button> | |
| 386 | + </template> | |
| 387 | + </el-table-column> | |
| 388 | + </NCC-table> | |
| 389 | + </div> | |
| 390 | + | |
| 391 | + <!-- 计算股份弹窗 --> | |
| 392 | + <el-dialog | |
| 393 | + title="计算门店股份" | |
| 394 | + :visible="calculateDialogVisible" | |
| 395 | + width="500px" | |
| 396 | + :close-on-click-modal="false" | |
| 397 | + @close="handleCalculateDialogClose" | |
| 398 | + > | |
| 399 | + <el-form label-width="100px" label-position="right"> | |
| 400 | + <el-form-item label="统计月份" required> | |
| 401 | + <el-date-picker | |
| 402 | + v-model="calculateMonth" | |
| 403 | + type="month" | |
| 404 | + placeholder="请选择月份" | |
| 405 | + format="yyyyMM" | |
| 406 | + value-format="yyyyMM" | |
| 407 | + style="width: 100%" | |
| 408 | + /> | |
| 409 | + </el-form-item> | |
| 410 | + <el-form-item label="门店" required> | |
| 411 | + <el-select | |
| 412 | + v-model="calculateStoreId" | |
| 413 | + placeholder="请选择门店(不选则计算所有门店)" | |
| 414 | + clearable | |
| 415 | + filterable | |
| 416 | + style="width: 100%" | |
| 417 | + > | |
| 418 | + <el-option | |
| 419 | + v-for="store in storeOptions" | |
| 420 | + :key="store.value" | |
| 421 | + :label="store.label" | |
| 422 | + :value="store.value" | |
| 423 | + /> | |
| 424 | + </el-select> | |
| 425 | + </el-form-item> | |
| 426 | + </el-form> | |
| 427 | + <div slot="footer" class="dialog-footer"> | |
| 428 | + <el-button @click="handleCalculateDialogClose">取消</el-button> | |
| 429 | + <el-button | |
| 430 | + type="primary" | |
| 431 | + @click="handleCalculateConfirm" | |
| 432 | + :loading="calculateLoading" | |
| 433 | + > | |
| 434 | + 确定 | |
| 435 | + </el-button> | |
| 436 | + </div> | |
| 437 | + </el-dialog> | |
| 438 | + | |
| 439 | + <!-- 详情弹窗 --> | |
| 440 | + <shop-stock-detail-dialog | |
| 441 | + :visible="detailVisible" | |
| 442 | + :detail-data="currentDetailData" | |
| 443 | + @close="handleDetailClose" | |
| 444 | + /> | |
| 24 | 445 | </div> |
| 25 | 446 | </template> |
| 26 | 447 | |
| 27 | 448 | <script> |
| 449 | +import { getShopStockList, generateShopStock, getStoreSelector } from '@/api/extend/shopStock' | |
| 450 | +import ShopStockDetailDialog from './shop-stock-detail-dialog.vue' | |
| 451 | + | |
| 28 | 452 | export default { |
| 29 | 453 | name: 'ShopStock', |
| 454 | + components: { | |
| 455 | + ShopStockDetailDialog | |
| 456 | + }, | |
| 30 | 457 | data() { |
| 458 | + // 获取当前月份 | |
| 459 | + const getCurrentMonth = () => { | |
| 460 | + const now = new Date() | |
| 461 | + const year = now.getFullYear() | |
| 462 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 463 | + return `${year}${month}` | |
| 464 | + } | |
| 465 | + | |
| 31 | 466 | return { |
| 32 | - loading: false | |
| 467 | + loading: false, | |
| 468 | + calculateLoading: false, | |
| 469 | + exportLoading: false, | |
| 470 | + list: [], | |
| 471 | + storeOptions: [], | |
| 472 | + calculateDialogVisible: false, | |
| 473 | + calculateMonth: getCurrentMonth(), | |
| 474 | + calculateStoreId: '', | |
| 475 | + detailVisible: false, | |
| 476 | + currentDetailData: null, | |
| 477 | + queryParams: { | |
| 478 | + statisticsMonth: getCurrentMonth(), // yyyyMM 格式 | |
| 479 | + storeId: '' | |
| 480 | + } | |
| 33 | 481 | } |
| 34 | 482 | }, |
| 483 | + created() { | |
| 484 | + this.getStoreOptions() | |
| 485 | + this.getList() | |
| 486 | + }, | |
| 35 | 487 | methods: { |
| 36 | - handleRefresh() { | |
| 488 | + // 获取门店选项 | |
| 489 | + async getStoreOptions() { | |
| 490 | + try { | |
| 491 | + const response = await getStoreSelector() | |
| 492 | + if (response.code === 200 && response.data) { | |
| 493 | + this.storeOptions = response.data.list.map(item => ({ | |
| 494 | + value: item.id, | |
| 495 | + label: item.fullName | |
| 496 | + })) | |
| 497 | + } | |
| 498 | + } catch (error) { | |
| 499 | + console.error('获取门店列表失败:', error) | |
| 500 | + } | |
| 501 | + }, | |
| 502 | + | |
| 503 | + // 获取列表数据 | |
| 504 | + async getList() { | |
| 37 | 505 | this.loading = true |
| 38 | - setTimeout(() => { | |
| 506 | + try { | |
| 507 | + const params = { | |
| 508 | + StatisticsMonth: this.queryParams.statisticsMonth || undefined, | |
| 509 | + StoreId: this.queryParams.storeId || undefined | |
| 510 | + } | |
| 511 | + | |
| 512 | + const response = await getShopStockList(params) | |
| 513 | + console.log(response) | |
| 514 | + if (response.code === 200) { | |
| 515 | + this.list = response.data.data || [] | |
| 516 | + } else { | |
| 517 | + this.$message.error(response.msg || '获取数据失败') | |
| 518 | + } | |
| 519 | + } catch (error) { | |
| 520 | + console.error('获取门店股份列表失败:', error) | |
| 521 | + this.$message.error('获取数据失败') | |
| 522 | + } finally { | |
| 39 | 523 | this.loading = false |
| 40 | - this.$message.success('刷新成功') | |
| 41 | - }, 500) | |
| 524 | + } | |
| 525 | + }, | |
| 526 | + | |
| 527 | + // 搜索 | |
| 528 | + handleQuery() { | |
| 529 | + this.getList() | |
| 530 | + }, | |
| 531 | + | |
| 532 | + // 重置搜索 | |
| 533 | + resetQuery() { | |
| 534 | + const getCurrentMonth = () => { | |
| 535 | + const now = new Date() | |
| 536 | + const year = now.getFullYear() | |
| 537 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 538 | + return `${year}${month}` | |
| 539 | + } | |
| 540 | + | |
| 541 | + this.queryParams = { | |
| 542 | + statisticsMonth: getCurrentMonth(), | |
| 543 | + storeId: '' | |
| 544 | + } | |
| 545 | + this.getList() | |
| 546 | + }, | |
| 547 | + | |
| 548 | + // 显示计算股份弹窗 | |
| 549 | + showCalculateDialog() { | |
| 550 | + const getCurrentMonth = () => { | |
| 551 | + const now = new Date() | |
| 552 | + const year = now.getFullYear() | |
| 553 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 554 | + return `${year}${month}` | |
| 555 | + } | |
| 556 | + this.calculateMonth = getCurrentMonth() | |
| 557 | + this.calculateStoreId = '' | |
| 558 | + this.calculateDialogVisible = true | |
| 559 | + }, | |
| 560 | + | |
| 561 | + // 关闭计算股份弹窗 | |
| 562 | + handleCalculateDialogClose() { | |
| 563 | + this.calculateDialogVisible = false | |
| 564 | + }, | |
| 565 | + | |
| 566 | + // 确认计算股份 | |
| 567 | + async handleCalculateConfirm() { | |
| 568 | + if (!this.calculateMonth) { | |
| 569 | + this.$message.warning('请选择统计月份') | |
| 570 | + return | |
| 571 | + } | |
| 572 | + | |
| 573 | + this.calculateLoading = true | |
| 574 | + try { | |
| 575 | + const data = { | |
| 576 | + statisticsMonth: this.calculateMonth, | |
| 577 | + storeId: this.calculateStoreId || undefined | |
| 578 | + } | |
| 579 | + | |
| 580 | + const response = await generateShopStock(data) | |
| 581 | + if (response.code === 200) { | |
| 582 | + this.$message.success('计算股份成功') | |
| 583 | + this.calculateDialogVisible = false | |
| 584 | + this.getList() | |
| 585 | + } else { | |
| 586 | + this.$message.error(response.msg || '计算股份失败') | |
| 587 | + } | |
| 588 | + } catch (error) { | |
| 589 | + console.error('计算股份失败:', error) | |
| 590 | + this.$message.error(error.message || '计算股份失败') | |
| 591 | + } finally { | |
| 592 | + this.calculateLoading = false | |
| 593 | + } | |
| 594 | + }, | |
| 595 | + | |
| 596 | + // 显示详情 | |
| 597 | + showDetail(row) { | |
| 598 | + this.currentDetailData = row | |
| 599 | + this.detailVisible = true | |
| 600 | + }, | |
| 601 | + | |
| 602 | + // 关闭详情弹窗 | |
| 603 | + handleDetailClose() { | |
| 604 | + this.detailVisible = false | |
| 605 | + this.currentDetailData = null | |
| 606 | + }, | |
| 607 | + | |
| 608 | + // 导出功能 | |
| 609 | + async handleExport() { | |
| 610 | + if (!this.list || this.list.length === 0) { | |
| 611 | + this.$message.warning('暂无数据可导出') | |
| 612 | + return | |
| 613 | + } | |
| 614 | + | |
| 615 | + this.exportLoading = true | |
| 616 | + try { | |
| 617 | + // 动态导入 xlsx 库 | |
| 618 | + const XLSX = await import('xlsx') | |
| 619 | + | |
| 620 | + // 构建表头(根据后端DTO字段的中文映射) | |
| 621 | + const headers = [ | |
| 622 | + '门店名称', | |
| 623 | + '统计月份', | |
| 624 | + '主营收入', | |
| 625 | + '生美消耗业绩', | |
| 626 | + '科美消耗业绩', | |
| 627 | + '医美消耗业绩', | |
| 628 | + '合作消费业绩', | |
| 629 | + '产品消耗业绩', | |
| 630 | + '其他消耗业绩', | |
| 631 | + '其他收入', | |
| 632 | + '预收款', | |
| 633 | + '实际退款', | |
| 634 | + '应收', | |
| 635 | + '银行存款', | |
| 636 | + '主营成本-产品', | |
| 637 | + '主营成本-福田', | |
| 638 | + '主营成本-毛巾', | |
| 639 | + '主营成本-科技部', | |
| 640 | + '主营成本-管理费', | |
| 641 | + '主营成本-合作', | |
| 642 | + '主营成本-大项目', | |
| 643 | + '其他成本', | |
| 644 | + '健康师底薪', | |
| 645 | + '店助底薪', | |
| 646 | + '店助主任底薪', | |
| 647 | + '店长底薪', | |
| 648 | + '总经理/经理底薪', | |
| 649 | + '健康师提成', | |
| 650 | + '店助提成', | |
| 651 | + '店助主任提成', | |
| 652 | + '店长提成', | |
| 653 | + '总经理/经理提成', | |
| 654 | + '手工', | |
| 655 | + '出勤', | |
| 656 | + '手机保管费', | |
| 657 | + '人头', | |
| 658 | + '门店T区', | |
| 659 | + '社保', | |
| 660 | + '门店房租', | |
| 661 | + '宿舍房租', | |
| 662 | + '当期费用', | |
| 663 | + '当前费用-秦董', | |
| 664 | + '财务费用', | |
| 665 | + '奖励-医美', | |
| 666 | + '奖励-其他', | |
| 667 | + '奖励-大单奖', | |
| 668 | + '奖励-首单奖', | |
| 669 | + '奖励', | |
| 670 | + '其他1', | |
| 671 | + '其他2', | |
| 672 | + '利润', | |
| 673 | + '财务利润' | |
| 674 | + ] | |
| 675 | + | |
| 676 | + // 构建数据行 | |
| 677 | + const dataRows = this.list.map(item => [ | |
| 678 | + item.StoreName || '无', | |
| 679 | + this.formatMonth(item.StatisticsMonth) || '无', | |
| 680 | + this.formatMoney(item.MainIncome), | |
| 681 | + this.formatMoney(item.ConsumeLifeBeauty), | |
| 682 | + this.formatMoney(item.ConsumeTechBeauty), | |
| 683 | + this.formatMoney(item.ConsumeMedicalBeauty), | |
| 684 | + this.formatMoney(item.ConsumeCooperation), | |
| 685 | + this.formatMoney(item.ConsumeProduct), | |
| 686 | + this.formatMoney(item.ConsumeOther), | |
| 687 | + this.formatMoney(item.OtherIncome), | |
| 688 | + this.formatMoney(item.AdvanceReceipt), | |
| 689 | + this.formatMoney(item.Refund), | |
| 690 | + this.formatMoney(item.Receivables), | |
| 691 | + this.formatMoney(item.BankDeposit), | |
| 692 | + this.formatMoney(item.CostProduct), | |
| 693 | + this.formatMoney(item.CostFutian), | |
| 694 | + this.formatMoney(item.CostTowel), | |
| 695 | + this.formatMoney(item.CostTechDept), | |
| 696 | + this.formatMoney(item.CostManagementFee), | |
| 697 | + this.formatMoney(item.CostCooperation), | |
| 698 | + this.formatMoney(item.CostMajorProject), | |
| 699 | + this.formatMoney(item.CostOther), | |
| 700 | + this.formatMoney(item.SalaryBaseHealthCoach), | |
| 701 | + this.formatMoney(item.SalaryBaseAssistant), | |
| 702 | + this.formatMoney(item.SalaryBaseDirector), | |
| 703 | + this.formatMoney(item.SalaryBaseStoreManager), | |
| 704 | + this.formatMoney(item.SalaryBaseGeneralManager), | |
| 705 | + this.formatMoney(item.SalaryCommissionHealthCoach), | |
| 706 | + this.formatMoney(item.SalaryCommissionAssistant), | |
| 707 | + this.formatMoney(item.SalaryCommissionDirector), | |
| 708 | + this.formatMoney(item.SalaryCommissionStoreManager), | |
| 709 | + this.formatMoney(item.SalaryCommissionGeneralManager), | |
| 710 | + this.formatMoney(item.SalaryManual), | |
| 711 | + this.formatMoney(item.SalaryAttendance), | |
| 712 | + this.formatMoney(item.SalaryPhoneCustody), | |
| 713 | + this.formatMoney(item.SalaryHeadcountReward), | |
| 714 | + this.formatMoney(item.SalaryTZone), | |
| 715 | + this.formatMoney(item.SocialSecurity), | |
| 716 | + this.formatMoney(item.StoreRent), | |
| 717 | + this.formatMoney(item.DormRent), | |
| 718 | + this.formatMoney(item.CurrentPeriodExpense), | |
| 719 | + this.formatMoney(item.CurrentPeriodExpenseQin), | |
| 720 | + this.formatMoney(item.FinancialFee), | |
| 721 | + this.formatMoney(item.RewardMedicalBeauty), | |
| 722 | + this.formatMoney(item.RewardOther), | |
| 723 | + this.formatMoney(item.RewardLargeOrder), | |
| 724 | + this.formatMoney(item.RewardFirstOrder), | |
| 725 | + this.formatMoney(item.RewardGeneral), | |
| 726 | + this.formatMoney(item.Other1), | |
| 727 | + this.formatMoney(item.Other2), | |
| 728 | + this.formatMoney(item.Profit), | |
| 729 | + this.formatMoney(item.FinancialProfit) | |
| 730 | + ]) | |
| 731 | + | |
| 732 | + // 合并表头和数据 | |
| 733 | + const excelData = [headers, ...dataRows] | |
| 734 | + | |
| 735 | + // 创建工作表 | |
| 736 | + const ws = XLSX.utils.aoa_to_sheet(excelData) | |
| 737 | + | |
| 738 | + // 设置列宽 | |
| 739 | + const colWidths = headers.map(() => ({ wch: 15 })) | |
| 740 | + ws['!cols'] = colWidths | |
| 741 | + | |
| 742 | + // 创建工作簿 | |
| 743 | + const wb = XLSX.utils.book_new() | |
| 744 | + XLSX.utils.book_append_sheet(wb, ws, '门店股份') | |
| 745 | + | |
| 746 | + // 生成文件名 | |
| 747 | + const now = new Date() | |
| 748 | + const timestamp = now.getFullYear() + | |
| 749 | + String(now.getMonth() + 1).padStart(2, '0') + | |
| 750 | + String(now.getDate()).padStart(2, '0') + | |
| 751 | + String(now.getHours()).padStart(2, '0') + | |
| 752 | + String(now.getMinutes()).padStart(2, '0') + | |
| 753 | + String(now.getSeconds()).padStart(2, '0') | |
| 754 | + const fileName = `门店股份_${timestamp}.xlsx` | |
| 755 | + | |
| 756 | + // 导出文件 | |
| 757 | + XLSX.writeFile(wb, fileName) | |
| 758 | + | |
| 759 | + this.$message.success('导出成功') | |
| 760 | + } catch (error) { | |
| 761 | + console.error('导出失败:', error) | |
| 762 | + this.$message.error('导出失败,请重试') | |
| 763 | + } finally { | |
| 764 | + this.exportLoading = false | |
| 765 | + } | |
| 766 | + }, | |
| 767 | + | |
| 768 | + // 格式化金额 | |
| 769 | + formatMoney(value) { | |
| 770 | + if (value === null || value === undefined || value === '') { | |
| 771 | + return '0.00' | |
| 772 | + } | |
| 773 | + return Number(value).toFixed(2) | |
| 774 | + }, | |
| 775 | + | |
| 776 | + // 格式化月份 | |
| 777 | + formatMonth(value) { | |
| 778 | + if (!value || value.length !== 6) { | |
| 779 | + return value || '无' | |
| 780 | + } | |
| 781 | + const year = value.substring(0, 4) | |
| 782 | + const month = value.substring(4, 6) | |
| 783 | + return `${year}-${month}` | |
| 42 | 784 | } |
| 43 | 785 | } |
| 44 | 786 | } |
| ... | ... | @@ -81,12 +823,54 @@ export default { |
| 81 | 823 | } |
| 82 | 824 | } |
| 83 | 825 | |
| 84 | -.content-container { | |
| 826 | +.search-container { | |
| 827 | + margin-bottom: 20px; | |
| 85 | 828 | padding: 20px; |
| 86 | 829 | background: #fff; |
| 87 | 830 | border-radius: 8px; |
| 88 | 831 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| 89 | - min-height: 400px; | |
| 90 | 832 | } |
| 91 | -</style> | |
| 92 | 833 | |
| 834 | +.table-container { | |
| 835 | + margin-bottom: 20px; | |
| 836 | + padding: 20px; | |
| 837 | + background: #fff; | |
| 838 | + border-radius: 8px; | |
| 839 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| 840 | +} | |
| 841 | + | |
| 842 | +.store-name { | |
| 843 | + display: flex; | |
| 844 | + align-items: center; | |
| 845 | + gap: 6px; | |
| 846 | + | |
| 847 | + .store-icon { | |
| 848 | + color: #409EFF; | |
| 849 | + font-size: 16px; | |
| 850 | + } | |
| 851 | +} | |
| 852 | + | |
| 853 | +.highlight { | |
| 854 | + color: #409EFF; | |
| 855 | + font-weight: 600; | |
| 856 | +} | |
| 857 | + | |
| 858 | +// 表格样式优化 | |
| 859 | +::v-deep .el-table { | |
| 860 | + .el-table__header-wrapper { | |
| 861 | + th { | |
| 862 | + background-color: #f5f7fa; | |
| 863 | + color: #606266; | |
| 864 | + font-weight: 600; | |
| 865 | + } | |
| 866 | + } | |
| 867 | + | |
| 868 | + .el-table__body-wrapper { | |
| 869 | + .el-table__row { | |
| 870 | + &:hover { | |
| 871 | + background-color: #f5f7fa; | |
| 872 | + } | |
| 873 | + } | |
| 874 | + } | |
| 875 | +} | |
| 876 | +</style> | ... | ... |
antis-ncc-admin/src/views/wageManagement/tech-general-manager-detail-dialog.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + title="科技部总经理工资详情" | |
| 4 | + :visible="visible" | |
| 5 | + width="1400px" | |
| 6 | + :close-on-click-modal="false" | |
| 7 | + @close="handleClose" | |
| 8 | + class="detail-dialog" | |
| 9 | + > | |
| 10 | + <div v-if="detailData" class="detail-content"> | |
| 11 | + <!-- 基本信息 --> | |
| 12 | + <div class="detail-section"> | |
| 13 | + <div class="section-title"> | |
| 14 | + <i class="el-icon-user"></i> | |
| 15 | + <span>基本信息</span> | |
| 16 | + </div> | |
| 17 | + <div class="section-content"> | |
| 18 | + <div class="info-row"> | |
| 19 | + <div class="info-item"> | |
| 20 | + <span class="label">员工姓名:</span> | |
| 21 | + <span class="value">{{ detailData.EmployeeName || '无' }}</span> | |
| 22 | + </div> | |
| 23 | + <div class="info-item"> | |
| 24 | + <span class="label">员工账号:</span> | |
| 25 | + <span class="value">{{ detailData.EmployeeAccount || '无' }}</span> | |
| 26 | + </div> | |
| 27 | + <div class="info-item"> | |
| 28 | + <span class="label">核算岗位:</span> | |
| 29 | + <span class="value">{{ detailData.Position || '无' }}</span> | |
| 30 | + </div> | |
| 31 | + <div class="info-item"> | |
| 32 | + <span class="label">统计月份:</span> | |
| 33 | + <span class="value">{{ detailData.StatisticsMonth || '无' }}</span> | |
| 34 | + </div> | |
| 35 | + <div class="info-item" v-if="detailData.IsTerminated !== undefined && detailData.IsTerminated !== null"> | |
| 36 | + <span class="label">是否离职:</span> | |
| 37 | + <el-tag :type="detailData.IsTerminated === 1 ? 'danger' : 'success'" size="mini"> | |
| 38 | + {{ detailData.IsTerminated === 1 ? '已离职' : '在职' }} | |
| 39 | + </el-tag> | |
| 40 | + </div> | |
| 41 | + <div class="info-item" v-if="detailData.IsLocked !== undefined && detailData.IsLocked !== null"> | |
| 42 | + <span class="label">锁定状态:</span> | |
| 43 | + <el-tag :type="detailData.IsLocked === 1 ? 'danger' : 'success'" size="mini"> | |
| 44 | + {{ detailData.IsLocked === 1 ? '已锁定' : '未锁定' }} | |
| 45 | + </el-tag> | |
| 46 | + </div> | |
| 47 | + </div> | |
| 48 | + </div> | |
| 49 | + </div> | |
| 50 | + | |
| 51 | + <!-- 业绩信息 --> | |
| 52 | + <div class="detail-section"> | |
| 53 | + <div class="section-title"> | |
| 54 | + <i class="el-icon-trophy"></i> | |
| 55 | + <span>业绩信息</span> | |
| 56 | + </div> | |
| 57 | + <div class="section-content"> | |
| 58 | + <div class="info-row"> | |
| 59 | + <div class="info-item"> | |
| 60 | + <span class="label">溯源金额:</span> | |
| 61 | + <span class="value highlight">{{ formatMoney(detailData.TraceabilityAmount) }}</span> | |
| 62 | + </div> | |
| 63 | + <div class="info-item"> | |
| 64 | + <span class="label">Cell金额:</span> | |
| 65 | + <span class="value highlight">{{ formatMoney(detailData.CellAmount) }}</span> | |
| 66 | + </div> | |
| 67 | + </div> | |
| 68 | + </div> | |
| 69 | + </div> | |
| 70 | + | |
| 71 | + <!-- 提成信息 --> | |
| 72 | + <div class="detail-section"> | |
| 73 | + <div class="section-title"> | |
| 74 | + <i class="el-icon-money"></i> | |
| 75 | + <span>提成信息</span> | |
| 76 | + </div> | |
| 77 | + <div class="section-content"> | |
| 78 | + <div class="info-row"> | |
| 79 | + <div class="info-item"> | |
| 80 | + <span class="label">溯源金额提成比例:</span> | |
| 81 | + <span class="value">{{ formatPercent(detailData.TraceabilityCommissionRate) }}</span> | |
| 82 | + </div> | |
| 83 | + <div class="info-item"> | |
| 84 | + <span class="label">溯源金额提成金额:</span> | |
| 85 | + <span class="value highlight">{{ formatMoney(detailData.TraceabilityCommissionAmount) }}</span> | |
| 86 | + </div> | |
| 87 | + <div class="info-item"> | |
| 88 | + <span class="label">Cell金额提成比例:</span> | |
| 89 | + <span class="value">{{ formatPercent(detailData.CellCommissionRate) }}</span> | |
| 90 | + </div> | |
| 91 | + <div class="info-item"> | |
| 92 | + <span class="label">Cell金额提成金额:</span> | |
| 93 | + <span class="value highlight">{{ formatMoney(detailData.CellCommissionAmount) }}</span> | |
| 94 | + </div> | |
| 95 | + <div class="info-item"> | |
| 96 | + <span class="label">提成合计:</span> | |
| 97 | + <span class="value highlight">{{ formatMoney(detailData.TotalCommission) }}</span> | |
| 98 | + </div> | |
| 99 | + </div> | |
| 100 | + </div> | |
| 101 | + </div> | |
| 102 | + | |
| 103 | + <!-- 工资信息 --> | |
| 104 | + <div class="detail-section"> | |
| 105 | + <div class="section-title"> | |
| 106 | + <i class="el-icon-wallet"></i> | |
| 107 | + <span>工资信息</span> | |
| 108 | + </div> | |
| 109 | + <div class="section-content"> | |
| 110 | + <div class="info-row"> | |
| 111 | + <div class="info-item"> | |
| 112 | + <span class="label">底薪:</span> | |
| 113 | + <span class="value">{{ formatMoney(detailData.BaseSalary) }}</span> | |
| 114 | + </div> | |
| 115 | + <div class="info-item"> | |
| 116 | + <span class="label">在店天数:</span> | |
| 117 | + <span class="value">{{ detailData.WorkingDays || '0' }}</span> | |
| 118 | + </div> | |
| 119 | + <div class="info-item"> | |
| 120 | + <span class="label">请假天数:</span> | |
| 121 | + <span class="value">{{ detailData.LeaveDays || '0' }}</span> | |
| 122 | + </div> | |
| 123 | + <div class="info-item"> | |
| 124 | + <span class="label">核算应发工资:</span> | |
| 125 | + <span class="value highlight">{{ formatMoney(detailData.CalculatedGrossSalary) }}</span> | |
| 126 | + </div> | |
| 127 | + <div class="info-item"> | |
| 128 | + <span class="label">最终应发工资:</span> | |
| 129 | + <span class="value highlight">{{ formatMoney(detailData.FinalGrossSalary) }}</span> | |
| 130 | + </div> | |
| 131 | + </div> | |
| 132 | + </div> | |
| 133 | + </div> | |
| 134 | + | |
| 135 | + <!-- 补贴信息 --> | |
| 136 | + <div class="detail-section"> | |
| 137 | + <div class="section-title"> | |
| 138 | + <i class="el-icon-circle-plus"></i> | |
| 139 | + <span>补贴信息</span> | |
| 140 | + </div> | |
| 141 | + <div class="section-content"> | |
| 142 | + <div class="info-row"> | |
| 143 | + <div class="info-item"> | |
| 144 | + <span class="label">当月培训补贴:</span> | |
| 145 | + <span class="value">{{ formatMoney(detailData.MonthlyTrainingSubsidy) }}</span> | |
| 146 | + </div> | |
| 147 | + <div class="info-item"> | |
| 148 | + <span class="label">当月交通补贴:</span> | |
| 149 | + <span class="value">{{ formatMoney(detailData.MonthlyTransportSubsidy) }}</span> | |
| 150 | + </div> | |
| 151 | + <div class="info-item"> | |
| 152 | + <span class="label">上月培训补贴:</span> | |
| 153 | + <span class="value">{{ formatMoney(detailData.LastMonthTrainingSubsidy) }}</span> | |
| 154 | + </div> | |
| 155 | + <div class="info-item"> | |
| 156 | + <span class="label">上月交通补贴:</span> | |
| 157 | + <span class="value">{{ formatMoney(detailData.LastMonthTransportSubsidy) }}</span> | |
| 158 | + </div> | |
| 159 | + <div class="info-item"> | |
| 160 | + <span class="label">补贴合计:</span> | |
| 161 | + <span class="value highlight">{{ formatMoney(detailData.TotalSubsidy) }}</span> | |
| 162 | + </div> | |
| 163 | + </div> | |
| 164 | + </div> | |
| 165 | + </div> | |
| 166 | + | |
| 167 | + <!-- 扣款信息 --> | |
| 168 | + <div class="detail-section"> | |
| 169 | + <div class="section-title"> | |
| 170 | + <i class="el-icon-circle-minus"></i> | |
| 171 | + <span>扣款信息</span> | |
| 172 | + </div> | |
| 173 | + <div class="section-content"> | |
| 174 | + <div class="info-row"> | |
| 175 | + <div class="info-item"> | |
| 176 | + <span class="label">缺卡扣款:</span> | |
| 177 | + <span class="value">{{ formatMoney(detailData.MissingCard) }}</span> | |
| 178 | + </div> | |
| 179 | + <div class="info-item"> | |
| 180 | + <span class="label">迟到扣款:</span> | |
| 181 | + <span class="value">{{ formatMoney(detailData.LateArrival) }}</span> | |
| 182 | + </div> | |
| 183 | + <div class="info-item"> | |
| 184 | + <span class="label">请假扣款:</span> | |
| 185 | + <span class="value">{{ formatMoney(detailData.LeaveDeduction) }}</span> | |
| 186 | + </div> | |
| 187 | + <div class="info-item"> | |
| 188 | + <span class="label">扣社保:</span> | |
| 189 | + <span class="value">{{ formatMoney(detailData.SocialInsuranceDeduction) }}</span> | |
| 190 | + </div> | |
| 191 | + <div class="info-item"> | |
| 192 | + <span class="label">扣除奖励:</span> | |
| 193 | + <span class="value">{{ formatMoney(detailData.RewardDeduction) }}</span> | |
| 194 | + </div> | |
| 195 | + <div class="info-item"> | |
| 196 | + <span class="label">扣住宿费:</span> | |
| 197 | + <span class="value">{{ formatMoney(detailData.AccommodationDeduction) }}</span> | |
| 198 | + </div> | |
| 199 | + <div class="info-item"> | |
| 200 | + <span class="label">扣学习期费用:</span> | |
| 201 | + <span class="value">{{ formatMoney(detailData.StudyPeriodDeduction) }}</span> | |
| 202 | + </div> | |
| 203 | + <div class="info-item"> | |
| 204 | + <span class="label">扣工作服费用:</span> | |
| 205 | + <span class="value">{{ formatMoney(detailData.WorkClothesDeduction) }}</span> | |
| 206 | + </div> | |
| 207 | + <div class="info-item"> | |
| 208 | + <span class="label">扣款合计:</span> | |
| 209 | + <span class="value highlight">{{ formatMoney(detailData.TotalDeduction) }}</span> | |
| 210 | + </div> | |
| 211 | + </div> | |
| 212 | + </div> | |
| 213 | + </div> | |
| 214 | + | |
| 215 | + <!-- 其他信息 --> | |
| 216 | + <div class="detail-section"> | |
| 217 | + <div class="section-title"> | |
| 218 | + <i class="el-icon-document"></i> | |
| 219 | + <span>其他信息</span> | |
| 220 | + </div> | |
| 221 | + <div class="section-content"> | |
| 222 | + <div class="info-row"> | |
| 223 | + <div class="info-item"> | |
| 224 | + <span class="label">发奖金:</span> | |
| 225 | + <span class="value">{{ formatMoney(detailData.Bonus) }}</span> | |
| 226 | + </div> | |
| 227 | + <div class="info-item"> | |
| 228 | + <span class="label">退手机押金:</span> | |
| 229 | + <span class="value">{{ formatMoney(detailData.ReturnPhoneDeposit) }}</span> | |
| 230 | + </div> | |
| 231 | + <div class="info-item"> | |
| 232 | + <span class="label">退住宿押金:</span> | |
| 233 | + <span class="value">{{ formatMoney(detailData.ReturnAccommodationDeposit) }}</span> | |
| 234 | + </div> | |
| 235 | + <div class="info-item"> | |
| 236 | + <span class="label">补发上月:</span> | |
| 237 | + <span class="value">{{ formatMoney(detailData.LastMonthSupplement) }}</span> | |
| 238 | + </div> | |
| 239 | + </div> | |
| 240 | + </div> | |
| 241 | + </div> | |
| 242 | + | |
| 243 | + <!-- 支付信息 --> | |
| 244 | + <div class="detail-section"> | |
| 245 | + <div class="section-title"> | |
| 246 | + <i class="el-icon-credit-card"></i> | |
| 247 | + <span>支付信息</span> | |
| 248 | + </div> | |
| 249 | + <div class="section-content"> | |
| 250 | + <div class="info-row"> | |
| 251 | + <div class="info-item"> | |
| 252 | + <span class="label">实发工资:</span> | |
| 253 | + <span class="value highlight large">{{ formatMoney(detailData.ActualSalary) }}</span> | |
| 254 | + </div> | |
| 255 | + <div class="info-item"> | |
| 256 | + <span class="label">当月是否发放:</span> | |
| 257 | + <span class="value">{{ detailData.MonthlyPaymentStatus || '无' }}</span> | |
| 258 | + </div> | |
| 259 | + <div class="info-item"> | |
| 260 | + <span class="label">支付金额:</span> | |
| 261 | + <span class="value">{{ formatMoney(detailData.PaidAmount) }}</span> | |
| 262 | + </div> | |
| 263 | + <div class="info-item"> | |
| 264 | + <span class="label">待支付金额:</span> | |
| 265 | + <span class="value">{{ formatMoney(detailData.PendingAmount) }}</span> | |
| 266 | + </div> | |
| 267 | + <div class="info-item"> | |
| 268 | + <span class="label">当月支付总额:</span> | |
| 269 | + <span class="value highlight">{{ formatMoney(detailData.MonthlyTotalPayment) }}</span> | |
| 270 | + </div> | |
| 271 | + </div> | |
| 272 | + </div> | |
| 273 | + </div> | |
| 274 | + </div> | |
| 275 | + | |
| 276 | + <div v-else class="no-data"> | |
| 277 | + <i class="el-icon-warning"></i> | |
| 278 | + <span>暂无数据</span> | |
| 279 | + </div> | |
| 280 | + </el-dialog> | |
| 281 | +</template> | |
| 282 | + | |
| 283 | +<script> | |
| 284 | +export default { | |
| 285 | + name: 'TechGeneralManagerDetailDialog', | |
| 286 | + props: { | |
| 287 | + visible: { | |
| 288 | + type: Boolean, | |
| 289 | + default: false | |
| 290 | + }, | |
| 291 | + detailData: { | |
| 292 | + type: Object, | |
| 293 | + default: null | |
| 294 | + } | |
| 295 | + }, | |
| 296 | + methods: { | |
| 297 | + handleClose() { | |
| 298 | + this.$emit('update:visible', false) | |
| 299 | + this.$emit('close') | |
| 300 | + }, | |
| 301 | + formatMoney(value) { | |
| 302 | + if (value === null || value === undefined || value === '') { | |
| 303 | + return '0.00' | |
| 304 | + } | |
| 305 | + return Number(value).toFixed(2) | |
| 306 | + }, | |
| 307 | + formatPercent(value) { | |
| 308 | + if (value === null || value === undefined || value === '') { | |
| 309 | + return '0.00%' | |
| 310 | + } | |
| 311 | + return (Number(value) * 100).toFixed(2) + '%' | |
| 312 | + } | |
| 313 | + } | |
| 314 | +} | |
| 315 | +</script> | |
| 316 | + | |
| 317 | +<style lang="scss" scoped> | |
| 318 | +.detail-dialog { | |
| 319 | + .detail-content { | |
| 320 | + max-height: 70vh; | |
| 321 | + overflow-y: auto; | |
| 322 | + padding-right: 10px; | |
| 323 | + } | |
| 324 | + | |
| 325 | + .detail-section { | |
| 326 | + margin-bottom: 20px; | |
| 327 | + background: #fff; | |
| 328 | + border-radius: 8px; | |
| 329 | + padding: 20px; | |
| 330 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| 331 | + | |
| 332 | + .section-title { | |
| 333 | + display: flex; | |
| 334 | + align-items: center; | |
| 335 | + gap: 8px; | |
| 336 | + margin-bottom: 16px; | |
| 337 | + padding-bottom: 12px; | |
| 338 | + border-bottom: 2px solid #409EFF; | |
| 339 | + font-size: 16px; | |
| 340 | + font-weight: 600; | |
| 341 | + color: #303133; | |
| 342 | + | |
| 343 | + i { | |
| 344 | + color: #409EFF; | |
| 345 | + font-size: 18px; | |
| 346 | + } | |
| 347 | + } | |
| 348 | + | |
| 349 | + .section-content { | |
| 350 | + .info-row { | |
| 351 | + display: flex; | |
| 352 | + flex-wrap: wrap; | |
| 353 | + gap: 20px 40px; | |
| 354 | + | |
| 355 | + .info-item { | |
| 356 | + display: flex; | |
| 357 | + align-items: center; | |
| 358 | + min-width: 200px; | |
| 359 | + flex: 0 0 calc(33.333% - 27px); | |
| 360 | + | |
| 361 | + .label { | |
| 362 | + color: #606266; | |
| 363 | + font-size: 14px; | |
| 364 | + white-space: nowrap; | |
| 365 | + margin-right: 8px; | |
| 366 | + } | |
| 367 | + | |
| 368 | + .value { | |
| 369 | + color: #303133; | |
| 370 | + font-size: 14px; | |
| 371 | + font-weight: 500; | |
| 372 | + | |
| 373 | + &.highlight { | |
| 374 | + color: #409EFF; | |
| 375 | + font-weight: 600; | |
| 376 | + } | |
| 377 | + | |
| 378 | + &.large { | |
| 379 | + font-size: 18px; | |
| 380 | + color: #67C23A; | |
| 381 | + } | |
| 382 | + } | |
| 383 | + } | |
| 384 | + } | |
| 385 | + } | |
| 386 | + } | |
| 387 | + | |
| 388 | + .no-data { | |
| 389 | + display: flex; | |
| 390 | + flex-direction: column; | |
| 391 | + align-items: center; | |
| 392 | + justify-content: center; | |
| 393 | + padding: 60px 20px; | |
| 394 | + color: #909399; | |
| 395 | + | |
| 396 | + i { | |
| 397 | + font-size: 48px; | |
| 398 | + margin-bottom: 16px; | |
| 399 | + } | |
| 400 | + | |
| 401 | + span { | |
| 402 | + font-size: 14px; | |
| 403 | + } | |
| 404 | + } | |
| 405 | +} | |
| 406 | + | |
| 407 | +// 滚动条样式 | |
| 408 | +.detail-content::-webkit-scrollbar { | |
| 409 | + width: 6px; | |
| 410 | +} | |
| 411 | + | |
| 412 | +.detail-content::-webkit-scrollbar-track { | |
| 413 | + background: #f1f1f1; | |
| 414 | + border-radius: 3px; | |
| 415 | +} | |
| 416 | + | |
| 417 | +.detail-content::-webkit-scrollbar-thumb { | |
| 418 | + background: #c1c1c1; | |
| 419 | + border-radius: 3px; | |
| 420 | + | |
| 421 | + &:hover { | |
| 422 | + background: #a8a8a8; | |
| 423 | + } | |
| 424 | +} | |
| 425 | +</style> | |
| 426 | + | ... | ... |
antis-ncc-admin/src/views/wageManagement/tech-general-managers.vue
| ... | ... | @@ -8,6 +8,14 @@ |
| 8 | 8 | </div> |
| 9 | 9 | <div class="header-right"> |
| 10 | 10 | <el-button |
| 11 | + type="success" | |
| 12 | + icon="el-icon-download" | |
| 13 | + @click="handleExport" | |
| 14 | + :loading="exportLoading" | |
| 15 | + > | |
| 16 | + 导出 | |
| 17 | + </el-button> | |
| 18 | + <el-button | |
| 11 | 19 | type="primary" |
| 12 | 20 | icon="el-icon-cpu" |
| 13 | 21 | @click="showCalculateDialog" |
| ... | ... | @@ -299,18 +307,27 @@ |
| 299 | 307 | </el-table-column> |
| 300 | 308 | </el-table-column> |
| 301 | 309 | |
| 302 | - <!-- 其他字段 --> | |
| 303 | - <el-table-column prop="StoreDetail" label="门店明细" width="200" align="center" fixed="right"> | |
| 310 | + <!-- 操作列 --> | |
| 311 | + <el-table-column label="操作" width="200" align="center" fixed="right"> | |
| 304 | 312 | <template slot-scope="scope"> |
| 305 | 313 | <el-button |
| 306 | 314 | type="text" |
| 307 | 315 | size="mini" |
| 316 | + icon="el-icon-view" | |
| 317 | + @click="showDetail(scope.row)" | |
| 318 | + > | |
| 319 | + 查看详情 | |
| 320 | + </el-button> | |
| 321 | + <el-button | |
| 322 | + type="text" | |
| 323 | + size="mini" | |
| 324 | + icon="el-icon-document" | |
| 308 | 325 | @click="showStoreDetail(scope.row)" |
| 309 | 326 | v-if="scope.row.StoreDetail" |
| 327 | + style="margin-left: 8px;" | |
| 310 | 328 | > |
| 311 | - 查看明细 | |
| 329 | + 门店明细 | |
| 312 | 330 | </el-button> |
| 313 | - <span v-else>无</span> | |
| 314 | 331 | </template> |
| 315 | 332 | </el-table-column> |
| 316 | 333 | </NCC-table> |
| ... | ... | @@ -358,6 +375,13 @@ |
| 358 | 375 | </div> |
| 359 | 376 | </el-dialog> |
| 360 | 377 | |
| 378 | + <!-- 详情弹窗 --> | |
| 379 | + <tech-general-manager-detail-dialog | |
| 380 | + :visible="detailVisible" | |
| 381 | + :detail-data="currentDetailData" | |
| 382 | + @close="handleDetailClose" | |
| 383 | + /> | |
| 384 | + | |
| 361 | 385 | <!-- 门店明细弹窗 --> |
| 362 | 386 | <el-dialog |
| 363 | 387 | title="门店明细" |
| ... | ... | @@ -411,9 +435,13 @@ |
| 411 | 435 | |
| 412 | 436 | <script> |
| 413 | 437 | import { getTechGeneralManagerSalaryList, calculateTechGeneralManagerSalary } from '@/api/extend/techGeneralManagerSalary' |
| 438 | +import TechGeneralManagerDetailDialog from './tech-general-manager-detail-dialog.vue' | |
| 414 | 439 | |
| 415 | 440 | export default { |
| 416 | 441 | name: 'TechGeneralManagerSalary', |
| 442 | + components: { | |
| 443 | + TechGeneralManagerDetailDialog | |
| 444 | + }, | |
| 417 | 445 | data() { |
| 418 | 446 | // 获取当前年月 |
| 419 | 447 | const getCurrentYear = () => { |
| ... | ... | @@ -429,11 +457,14 @@ export default { |
| 429 | 457 | return { |
| 430 | 458 | loading: false, |
| 431 | 459 | calculateLoading: false, |
| 460 | + exportLoading: false, | |
| 432 | 461 | list: [], |
| 433 | 462 | total: 0, |
| 434 | 463 | calculateDialogVisible: false, |
| 435 | 464 | calculateYear: getCurrentYear(), |
| 436 | 465 | calculateMonth: getCurrentMonth(), |
| 466 | + detailVisible: false, | |
| 467 | + currentDetailData: null, | |
| 437 | 468 | storeDetailVisible: false, |
| 438 | 469 | storeDetailList: [], |
| 439 | 470 | queryParams: { |
| ... | ... | @@ -604,6 +635,156 @@ export default { |
| 604 | 635 | this.storeDetailList = [] |
| 605 | 636 | }, |
| 606 | 637 | |
| 638 | + // 显示详情 | |
| 639 | + showDetail(row) { | |
| 640 | + this.currentDetailData = row | |
| 641 | + this.detailVisible = true | |
| 642 | + }, | |
| 643 | + | |
| 644 | + // 关闭详情弹窗 | |
| 645 | + handleDetailClose() { | |
| 646 | + this.detailVisible = false | |
| 647 | + this.currentDetailData = null | |
| 648 | + }, | |
| 649 | + | |
| 650 | + // 导出功能 | |
| 651 | + async handleExport() { | |
| 652 | + if (!this.list || this.list.length === 0) { | |
| 653 | + this.$message.warning('暂无数据可导出') | |
| 654 | + return | |
| 655 | + } | |
| 656 | + | |
| 657 | + this.exportLoading = true | |
| 658 | + try { | |
| 659 | + // 动态导入 xlsx 库 | |
| 660 | + const XLSX = await import('xlsx') | |
| 661 | + | |
| 662 | + // 构建表头(根据后端DTO字段的中文映射) | |
| 663 | + const headers = [ | |
| 664 | + '员工姓名', | |
| 665 | + '员工账号', | |
| 666 | + '核算岗位', | |
| 667 | + '统计月份', | |
| 668 | + '是否离职', | |
| 669 | + '溯源金额', | |
| 670 | + 'Cell金额', | |
| 671 | + '底薪', | |
| 672 | + '溯源金额提成比例', | |
| 673 | + '溯源金额提成金额', | |
| 674 | + 'Cell金额提成比例', | |
| 675 | + 'Cell金额提成金额', | |
| 676 | + '提成合计', | |
| 677 | + '在店天数', | |
| 678 | + '请假天数', | |
| 679 | + '核算应发工资', | |
| 680 | + '最终应发工资', | |
| 681 | + '当月培训补贴', | |
| 682 | + '当月交通补贴', | |
| 683 | + '上月培训补贴', | |
| 684 | + '上月交通补贴', | |
| 685 | + '补贴合计', | |
| 686 | + '缺卡扣款', | |
| 687 | + '迟到扣款', | |
| 688 | + '请假扣款', | |
| 689 | + '扣社保', | |
| 690 | + '扣除奖励', | |
| 691 | + '扣住宿费', | |
| 692 | + '扣学习期费用', | |
| 693 | + '扣工作服费用', | |
| 694 | + '扣款合计', | |
| 695 | + '发奖金', | |
| 696 | + '退手机押金', | |
| 697 | + '退住宿押金', | |
| 698 | + '补发上月', | |
| 699 | + '实发工资', | |
| 700 | + '当月是否发放', | |
| 701 | + '支付金额', | |
| 702 | + '待支付金额', | |
| 703 | + '当月支付总额', | |
| 704 | + '是否锁定' | |
| 705 | + ] | |
| 706 | + | |
| 707 | + // 构建数据行 | |
| 708 | + const dataRows = this.list.map(item => [ | |
| 709 | + item.EmployeeName || '无', | |
| 710 | + item.EmployeeAccount || '无', | |
| 711 | + item.Position || '无', | |
| 712 | + item.StatisticsMonth || '无', | |
| 713 | + item.IsTerminated === 1 ? '已离职' : '在职', | |
| 714 | + this.formatMoney(item.TraceabilityAmount), | |
| 715 | + this.formatMoney(item.CellAmount), | |
| 716 | + this.formatMoney(item.BaseSalary), | |
| 717 | + this.formatPercent(item.TraceabilityCommissionRate), | |
| 718 | + this.formatMoney(item.TraceabilityCommissionAmount), | |
| 719 | + this.formatPercent(item.CellCommissionRate), | |
| 720 | + this.formatMoney(item.CellCommissionAmount), | |
| 721 | + this.formatMoney(item.TotalCommission), | |
| 722 | + item.WorkingDays || '0', | |
| 723 | + item.LeaveDays || '0', | |
| 724 | + this.formatMoney(item.CalculatedGrossSalary), | |
| 725 | + this.formatMoney(item.FinalGrossSalary), | |
| 726 | + this.formatMoney(item.MonthlyTrainingSubsidy), | |
| 727 | + this.formatMoney(item.MonthlyTransportSubsidy), | |
| 728 | + this.formatMoney(item.LastMonthTrainingSubsidy), | |
| 729 | + this.formatMoney(item.LastMonthTransportSubsidy), | |
| 730 | + this.formatMoney(item.TotalSubsidy), | |
| 731 | + this.formatMoney(item.MissingCard), | |
| 732 | + this.formatMoney(item.LateArrival), | |
| 733 | + this.formatMoney(item.LeaveDeduction), | |
| 734 | + this.formatMoney(item.SocialInsuranceDeduction), | |
| 735 | + this.formatMoney(item.RewardDeduction), | |
| 736 | + this.formatMoney(item.AccommodationDeduction), | |
| 737 | + this.formatMoney(item.StudyPeriodDeduction), | |
| 738 | + this.formatMoney(item.WorkClothesDeduction), | |
| 739 | + this.formatMoney(item.TotalDeduction), | |
| 740 | + this.formatMoney(item.Bonus), | |
| 741 | + this.formatMoney(item.ReturnPhoneDeposit), | |
| 742 | + this.formatMoney(item.ReturnAccommodationDeposit), | |
| 743 | + this.formatMoney(item.LastMonthSupplement), | |
| 744 | + this.formatMoney(item.ActualSalary), | |
| 745 | + item.MonthlyPaymentStatus || '无', | |
| 746 | + this.formatMoney(item.PaidAmount), | |
| 747 | + this.formatMoney(item.PendingAmount), | |
| 748 | + this.formatMoney(item.MonthlyTotalPayment), | |
| 749 | + item.IsLocked === 1 ? '已锁定' : '未锁定' | |
| 750 | + ]) | |
| 751 | + | |
| 752 | + // 合并表头和数据 | |
| 753 | + const excelData = [headers, ...dataRows] | |
| 754 | + | |
| 755 | + // 创建工作表 | |
| 756 | + const ws = XLSX.utils.aoa_to_sheet(excelData) | |
| 757 | + | |
| 758 | + // 设置列宽 | |
| 759 | + const colWidths = headers.map(() => ({ wch: 15 })) | |
| 760 | + ws['!cols'] = colWidths | |
| 761 | + | |
| 762 | + // 创建工作簿 | |
| 763 | + const wb = XLSX.utils.book_new() | |
| 764 | + XLSX.utils.book_append_sheet(wb, ws, '科技部总经理工资') | |
| 765 | + | |
| 766 | + // 生成文件名 | |
| 767 | + const now = new Date() | |
| 768 | + const timestamp = now.getFullYear() + | |
| 769 | + String(now.getMonth() + 1).padStart(2, '0') + | |
| 770 | + String(now.getDate()).padStart(2, '0') + | |
| 771 | + String(now.getHours()).padStart(2, '0') + | |
| 772 | + String(now.getMinutes()).padStart(2, '0') + | |
| 773 | + String(now.getSeconds()).padStart(2, '0') | |
| 774 | + const fileName = `科技部总经理工资_${timestamp}.xlsx` | |
| 775 | + | |
| 776 | + // 导出文件 | |
| 777 | + XLSX.writeFile(wb, fileName) | |
| 778 | + | |
| 779 | + this.$message.success('导出成功') | |
| 780 | + } catch (error) { | |
| 781 | + console.error('导出失败:', error) | |
| 782 | + this.$message.error('导出失败,请重试') | |
| 783 | + } finally { | |
| 784 | + this.exportLoading = false | |
| 785 | + } | |
| 786 | + }, | |
| 787 | + | |
| 607 | 788 | // 格式化金额 |
| 608 | 789 | formatMoney(value) { |
| 609 | 790 | if (value === null || value === undefined || value === '') { | ... | ... |
antis-ncc-admin/src/views/wageManagement/tech-stock-detail-dialog.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + title="科技部股份详情" | |
| 4 | + :visible="visible" | |
| 5 | + width="1200px" | |
| 6 | + :close-on-click-modal="false" | |
| 7 | + @close="handleClose" | |
| 8 | + class="detail-dialog" | |
| 9 | + > | |
| 10 | + <div v-if="detailData" class="detail-content"> | |
| 11 | + <!-- 基本信息 --> | |
| 12 | + <div class="detail-section"> | |
| 13 | + <div class="section-title"> | |
| 14 | + <i class="el-icon-user"></i> | |
| 15 | + <span>基本信息</span> | |
| 16 | + </div> | |
| 17 | + <div class="section-content"> | |
| 18 | + <div class="info-row"> | |
| 19 | + <div class="info-item"> | |
| 20 | + <span class="label">部门名称:</span> | |
| 21 | + <span class="value">{{ detailData.DepartmentName || '无' }}</span> | |
| 22 | + </div> | |
| 23 | + <div class="info-item"> | |
| 24 | + <span class="label">统计月份:</span> | |
| 25 | + <span class="value">{{ formatMonth(detailData.StatisticsMonth) || '无' }}</span> | |
| 26 | + </div> | |
| 27 | + <div class="info-item" v-if="detailData.CreateTime"> | |
| 28 | + <span class="label">创建时间:</span> | |
| 29 | + <span class="value">{{ formatDateTime(detailData.CreateTime) }}</span> | |
| 30 | + </div> | |
| 31 | + <div class="info-item" v-if="detailData.UpdateTime"> | |
| 32 | + <span class="label">更新时间:</span> | |
| 33 | + <span class="value">{{ formatDateTime(detailData.UpdateTime) }}</span> | |
| 34 | + </div> | |
| 35 | + </div> | |
| 36 | + </div> | |
| 37 | + </div> | |
| 38 | + | |
| 39 | + <!-- 收入信息 --> | |
| 40 | + <div class="detail-section"> | |
| 41 | + <div class="section-title"> | |
| 42 | + <i class="el-icon-trophy"></i> | |
| 43 | + <span>收入信息</span> | |
| 44 | + </div> | |
| 45 | + <div class="section-content"> | |
| 46 | + <div class="info-row"> | |
| 47 | + <div class="info-item"> | |
| 48 | + <span class="label">收入:</span> | |
| 49 | + <span class="value highlight large">{{ formatMoney(detailData.Income) }}</span> | |
| 50 | + </div> | |
| 51 | + </div> | |
| 52 | + </div> | |
| 53 | + </div> | |
| 54 | + | |
| 55 | + <!-- 成本信息 --> | |
| 56 | + <div class="detail-section"> | |
| 57 | + <div class="section-title"> | |
| 58 | + <i class="el-icon-shopping-cart-2"></i> | |
| 59 | + <span>成本信息</span> | |
| 60 | + </div> | |
| 61 | + <div class="section-content"> | |
| 62 | + <div class="info-row"> | |
| 63 | + <div class="info-item"> | |
| 64 | + <span class="label">成本-报销:</span> | |
| 65 | + <span class="value">{{ formatMoney(detailData.CostReimbursement) }}</span> | |
| 66 | + </div> | |
| 67 | + <div class="info-item"> | |
| 68 | + <span class="label">成本-人工-老师底薪:</span> | |
| 69 | + <span class="value">{{ formatMoney(detailData.CostTeacherBase) }}</span> | |
| 70 | + </div> | |
| 71 | + <div class="info-item"> | |
| 72 | + <span class="label">成本-人工-手工费:</span> | |
| 73 | + <span class="value">{{ formatMoney(detailData.CostTeacherManual) }}</span> | |
| 74 | + </div> | |
| 75 | + <div class="info-item"> | |
| 76 | + <span class="label">成本-人工-开单提成:</span> | |
| 77 | + <span class="value">{{ formatMoney(detailData.CostTeacherBillingComm) }}</span> | |
| 78 | + </div> | |
| 79 | + <div class="info-item"> | |
| 80 | + <span class="label">成本-人工-消耗提成:</span> | |
| 81 | + <span class="value">{{ formatMoney(detailData.CostTeacherConsumeComm) }}</span> | |
| 82 | + </div> | |
| 83 | + <div class="info-item"> | |
| 84 | + <span class="label">成本-人工-专家提成:</span> | |
| 85 | + <span class="value">{{ formatMoney(detailData.CostTeacherExpertComm) }}</span> | |
| 86 | + </div> | |
| 87 | + <div class="info-item"> | |
| 88 | + <span class="label">成本-人工-加班:</span> | |
| 89 | + <span class="value">{{ formatMoney(detailData.CostTeacherOvertime) }}</span> | |
| 90 | + </div> | |
| 91 | + <div class="info-item"> | |
| 92 | + <span class="label">成本-人工-总经理底薪:</span> | |
| 93 | + <span class="value">{{ formatMoney(detailData.CostGMBase) }}</span> | |
| 94 | + </div> | |
| 95 | + <div class="info-item"> | |
| 96 | + <span class="label">成本-人工-总经理提成:</span> | |
| 97 | + <span class="value">{{ formatMoney(detailData.CostGMComm) }}</span> | |
| 98 | + </div> | |
| 99 | + <div class="info-item"> | |
| 100 | + <span class="label">成本-其他1:</span> | |
| 101 | + <span class="value">{{ formatMoney(detailData.CostOther1) }}</span> | |
| 102 | + </div> | |
| 103 | + <div class="info-item"> | |
| 104 | + <span class="label">成本-其他2:</span> | |
| 105 | + <span class="value">{{ formatMoney(detailData.CostOther2) }}</span> | |
| 106 | + </div> | |
| 107 | + </div> | |
| 108 | + </div> | |
| 109 | + </div> | |
| 110 | + | |
| 111 | + <!-- 奖励 --> | |
| 112 | + <div class="detail-section"> | |
| 113 | + <div class="section-title"> | |
| 114 | + <i class="el-icon-medal"></i> | |
| 115 | + <span>奖励</span> | |
| 116 | + </div> | |
| 117 | + <div class="section-content"> | |
| 118 | + <div class="info-row"> | |
| 119 | + <div class="info-item"> | |
| 120 | + <span class="label">奖励-科技部:</span> | |
| 121 | + <span class="value">{{ formatMoney(detailData.RewardTechDept) }}</span> | |
| 122 | + </div> | |
| 123 | + </div> | |
| 124 | + </div> | |
| 125 | + </div> | |
| 126 | + | |
| 127 | + <!-- 利润结果 --> | |
| 128 | + <div class="detail-section"> | |
| 129 | + <div class="section-title"> | |
| 130 | + <i class="el-icon-data-line"></i> | |
| 131 | + <span>利润结果</span> | |
| 132 | + </div> | |
| 133 | + <div class="section-content"> | |
| 134 | + <div class="info-row"> | |
| 135 | + <div class="info-item"> | |
| 136 | + <span class="label">利润:</span> | |
| 137 | + <span class="value highlight large">{{ formatMoney(detailData.Profit) }}</span> | |
| 138 | + </div> | |
| 139 | + </div> | |
| 140 | + </div> | |
| 141 | + </div> | |
| 142 | + </div> | |
| 143 | + <div slot="footer" class="dialog-footer"> | |
| 144 | + <el-button @click="handleClose">关闭</el-button> | |
| 145 | + </div> | |
| 146 | + </el-dialog> | |
| 147 | +</template> | |
| 148 | + | |
| 149 | +<script> | |
| 150 | +export default { | |
| 151 | + name: 'TechStockDetailDialog', | |
| 152 | + props: { | |
| 153 | + visible: { | |
| 154 | + type: Boolean, | |
| 155 | + default: false | |
| 156 | + }, | |
| 157 | + detailData: { | |
| 158 | + type: Object, | |
| 159 | + default: null | |
| 160 | + } | |
| 161 | + }, | |
| 162 | + methods: { | |
| 163 | + handleClose() { | |
| 164 | + this.$emit('close') | |
| 165 | + }, | |
| 166 | + formatMoney(value) { | |
| 167 | + if (value === null || value === undefined || value === '') { | |
| 168 | + return '0.00' | |
| 169 | + } | |
| 170 | + return Number(value).toFixed(2) | |
| 171 | + }, | |
| 172 | + formatMonth(value) { | |
| 173 | + if (!value || value.length !== 6) { | |
| 174 | + return value || '无' | |
| 175 | + } | |
| 176 | + const year = value.substring(0, 4) | |
| 177 | + const month = value.substring(4, 6) | |
| 178 | + return `${year}-${month}` | |
| 179 | + }, | |
| 180 | + formatDateTime(value) { | |
| 181 | + if (!value) return '无' | |
| 182 | + const date = new Date(value) | |
| 183 | + const year = date.getFullYear() | |
| 184 | + const month = String(date.getMonth() + 1).padStart(2, '0') | |
| 185 | + const day = String(date.getDate()).padStart(2, '0') | |
| 186 | + const hours = String(date.getHours()).padStart(2, '0') | |
| 187 | + const minutes = String(date.getMinutes()).padStart(2, '0') | |
| 188 | + const seconds = String(date.getSeconds()).padStart(2, '0') | |
| 189 | + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` | |
| 190 | + } | |
| 191 | + } | |
| 192 | +} | |
| 193 | +</script> | |
| 194 | + | |
| 195 | +<style lang="scss" scoped> | |
| 196 | +.detail-dialog { | |
| 197 | + .detail-content { | |
| 198 | + max-height: 70vh; | |
| 199 | + overflow-y: auto; | |
| 200 | + padding: 20px; | |
| 201 | + } | |
| 202 | + | |
| 203 | + .detail-section { | |
| 204 | + margin-bottom: 24px; | |
| 205 | + background: #f9f9f9; | |
| 206 | + border-radius: 8px; | |
| 207 | + padding: 16px; | |
| 208 | + | |
| 209 | + &:last-child { | |
| 210 | + margin-bottom: 0; | |
| 211 | + } | |
| 212 | + | |
| 213 | + .section-title { | |
| 214 | + display: flex; | |
| 215 | + align-items: center; | |
| 216 | + gap: 8px; | |
| 217 | + margin-bottom: 16px; | |
| 218 | + font-size: 16px; | |
| 219 | + font-weight: 600; | |
| 220 | + color: #303133; | |
| 221 | + border-bottom: 2px solid #409EFF; | |
| 222 | + padding-bottom: 8px; | |
| 223 | + | |
| 224 | + i { | |
| 225 | + color: #409EFF; | |
| 226 | + font-size: 18px; | |
| 227 | + } | |
| 228 | + } | |
| 229 | + | |
| 230 | + .section-content { | |
| 231 | + .info-row { | |
| 232 | + display: flex; | |
| 233 | + flex-wrap: wrap; | |
| 234 | + gap: 20px; | |
| 235 | + | |
| 236 | + .info-item { | |
| 237 | + flex: 0 0 calc(33.333% - 14px); | |
| 238 | + min-width: 250px; | |
| 239 | + display: flex; | |
| 240 | + align-items: center; | |
| 241 | + padding: 8px 12px; | |
| 242 | + background: #fff; | |
| 243 | + border-radius: 4px; | |
| 244 | + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); | |
| 245 | + | |
| 246 | + .label { | |
| 247 | + color: #606266; | |
| 248 | + font-weight: 500; | |
| 249 | + margin-right: 8px; | |
| 250 | + white-space: nowrap; | |
| 251 | + } | |
| 252 | + | |
| 253 | + .value { | |
| 254 | + color: #303133; | |
| 255 | + flex: 1; | |
| 256 | + text-align: right; | |
| 257 | + | |
| 258 | + &.highlight { | |
| 259 | + color: #409EFF; | |
| 260 | + font-weight: 600; | |
| 261 | + } | |
| 262 | + | |
| 263 | + &.large { | |
| 264 | + font-size: 18px; | |
| 265 | + } | |
| 266 | + } | |
| 267 | + } | |
| 268 | + } | |
| 269 | + } | |
| 270 | + } | |
| 271 | + | |
| 272 | + .dialog-footer { | |
| 273 | + text-align: right; | |
| 274 | + padding: 20px; | |
| 275 | + border-top: 1px solid #e4e7ed; | |
| 276 | + } | |
| 277 | +} | |
| 278 | + | |
| 279 | +// 滚动条样式 | |
| 280 | +.detail-content::-webkit-scrollbar { | |
| 281 | + width: 6px; | |
| 282 | +} | |
| 283 | + | |
| 284 | +.detail-content::-webkit-scrollbar-track { | |
| 285 | + background: #f1f1f1; | |
| 286 | + border-radius: 3px; | |
| 287 | +} | |
| 288 | + | |
| 289 | +.detail-content::-webkit-scrollbar-thumb { | |
| 290 | + background: #c1c1c1; | |
| 291 | + border-radius: 3px; | |
| 292 | + | |
| 293 | + &:hover { | |
| 294 | + background: #a8a8a8; | |
| 295 | + } | |
| 296 | +} | |
| 297 | +</style> | |
| 298 | + | ... | ... |
antis-ncc-admin/src/views/wageManagement/tech-stock.vue
| ... | ... | @@ -8,8 +8,24 @@ |
| 8 | 8 | </div> |
| 9 | 9 | <div class="header-right"> |
| 10 | 10 | <el-button |
| 11 | + type="success" | |
| 12 | + icon="el-icon-download" | |
| 13 | + @click="handleExport" | |
| 14 | + :loading="exportLoading" | |
| 15 | + > | |
| 16 | + 导出 | |
| 17 | + </el-button> | |
| 18 | + <el-button | |
| 19 | + type="primary" | |
| 20 | + icon="el-icon-cpu" | |
| 21 | + @click="showCalculateDialog" | |
| 22 | + :loading="calculateLoading" | |
| 23 | + > | |
| 24 | + 计算股份 | |
| 25 | + </el-button> | |
| 26 | + <el-button | |
| 11 | 27 | icon="el-icon-refresh" |
| 12 | - @click="handleRefresh" | |
| 28 | + @click="getList" | |
| 13 | 29 | :loading="loading" |
| 14 | 30 | > |
| 15 | 31 | 刷新 |
| ... | ... | @@ -17,28 +33,465 @@ |
| 17 | 33 | </div> |
| 18 | 34 | </div> |
| 19 | 35 | |
| 20 | - <!-- 内容区域 --> | |
| 21 | - <div class="content-container"> | |
| 22 | - <!-- 待开发 --> | |
| 36 | + <!-- 搜索区域 --> | |
| 37 | + <div class="search-container"> | |
| 38 | + <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="80px"> | |
| 39 | + <el-form-item label="统计月份" prop="statisticsMonth"> | |
| 40 | + <el-date-picker | |
| 41 | + v-model="queryParams.statisticsMonth" | |
| 42 | + type="month" | |
| 43 | + placeholder="选择月份" | |
| 44 | + format="yyyyMM" | |
| 45 | + value-format="yyyyMM" | |
| 46 | + style="width: 200px" | |
| 47 | + /> | |
| 48 | + </el-form-item> | |
| 49 | + <el-form-item label="部门" prop="departmentName"> | |
| 50 | + <el-select | |
| 51 | + v-model="queryParams.departmentName" | |
| 52 | + placeholder="请选择部门" | |
| 53 | + clearable | |
| 54 | + filterable | |
| 55 | + style="width: 200px" | |
| 56 | + > | |
| 57 | + <el-option label="科技一部" value="科技一部" /> | |
| 58 | + <el-option label="科技二部" value="科技二部" /> | |
| 59 | + </el-select> | |
| 60 | + </el-form-item> | |
| 61 | + <el-form-item> | |
| 62 | + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> | |
| 63 | + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button> | |
| 64 | + </el-form-item> | |
| 65 | + </el-form> | |
| 23 | 66 | </div> |
| 67 | + | |
| 68 | + <!-- 数据表格 --> | |
| 69 | + <div class="table-container"> | |
| 70 | + <NCC-table | |
| 71 | + v-loading="loading" | |
| 72 | + :data="list" | |
| 73 | + border | |
| 74 | + stripe | |
| 75 | + height="calc(100vh - 420px)" | |
| 76 | + :header-cell-style="{ background: '#f5f7fa', color: '#606266' }" | |
| 77 | + > | |
| 78 | + <!-- 基本信息 --> | |
| 79 | + <el-table-column prop="DepartmentName" label="部门名称" width="150" align="center" fixed="left"> | |
| 80 | + <template slot-scope="scope"> | |
| 81 | + <div class="department-name"> | |
| 82 | + <i class="el-icon-office-building department-icon"></i> | |
| 83 | + <span>{{ scope.row.DepartmentName || '无' }}</span> | |
| 84 | + </div> | |
| 85 | + </template> | |
| 86 | + </el-table-column> | |
| 87 | + <el-table-column prop="StatisticsMonth" label="统计月份" width="120" align="center" fixed="left"> | |
| 88 | + <template slot-scope="scope"> | |
| 89 | + <span>{{ formatMonth(scope.row.StatisticsMonth) || '无' }}</span> | |
| 90 | + </template> | |
| 91 | + </el-table-column> | |
| 92 | + | |
| 93 | + <!-- 收入信息 --> | |
| 94 | + <el-table-column label="收入信息" align="center"> | |
| 95 | + <el-table-column prop="Income" label="收入" width="120" align="center"> | |
| 96 | + <template slot-scope="scope"> | |
| 97 | + <span class="highlight">{{ formatMoney(scope.row.Income) }}</span> | |
| 98 | + </template> | |
| 99 | + </el-table-column> | |
| 100 | + </el-table-column> | |
| 101 | + | |
| 102 | + <!-- 成本信息 --> | |
| 103 | + <el-table-column label="成本信息" align="center"> | |
| 104 | + <el-table-column prop="CostReimbursement" label="成本-报销" width="120" align="center"> | |
| 105 | + <template slot-scope="scope"> | |
| 106 | + <span>{{ formatMoney(scope.row.CostReimbursement) }}</span> | |
| 107 | + </template> | |
| 108 | + </el-table-column> | |
| 109 | + <el-table-column prop="CostTeacherBase" label="成本-人工-老师底薪" width="160" align="center"> | |
| 110 | + <template slot-scope="scope"> | |
| 111 | + <span>{{ formatMoney(scope.row.CostTeacherBase) }}</span> | |
| 112 | + </template> | |
| 113 | + </el-table-column> | |
| 114 | + <el-table-column prop="CostTeacherManual" label="成本-人工-手工费" width="160" align="center"> | |
| 115 | + <template slot-scope="scope"> | |
| 116 | + <span>{{ formatMoney(scope.row.CostTeacherManual) }}</span> | |
| 117 | + </template> | |
| 118 | + </el-table-column> | |
| 119 | + <el-table-column prop="CostTeacherBillingComm" label="成本-人工-开单提成" width="160" align="center"> | |
| 120 | + <template slot-scope="scope"> | |
| 121 | + <span>{{ formatMoney(scope.row.CostTeacherBillingComm) }}</span> | |
| 122 | + </template> | |
| 123 | + </el-table-column> | |
| 124 | + <el-table-column prop="CostTeacherConsumeComm" label="成本-人工-消耗提成" width="160" align="center"> | |
| 125 | + <template slot-scope="scope"> | |
| 126 | + <span>{{ formatMoney(scope.row.CostTeacherConsumeComm) }}</span> | |
| 127 | + </template> | |
| 128 | + </el-table-column> | |
| 129 | + <el-table-column prop="CostTeacherExpertComm" label="成本-人工-专家提成" width="160" align="center"> | |
| 130 | + <template slot-scope="scope"> | |
| 131 | + <span>{{ formatMoney(scope.row.CostTeacherExpertComm) }}</span> | |
| 132 | + </template> | |
| 133 | + </el-table-column> | |
| 134 | + <el-table-column prop="CostTeacherOvertime" label="成本-人工-加班" width="140" align="center"> | |
| 135 | + <template slot-scope="scope"> | |
| 136 | + <span>{{ formatMoney(scope.row.CostTeacherOvertime) }}</span> | |
| 137 | + </template> | |
| 138 | + </el-table-column> | |
| 139 | + <el-table-column prop="CostGMBase" label="成本-人工-总经理底薪" width="170" align="center"> | |
| 140 | + <template slot-scope="scope"> | |
| 141 | + <span>{{ formatMoney(scope.row.CostGMBase) }}</span> | |
| 142 | + </template> | |
| 143 | + </el-table-column> | |
| 144 | + <el-table-column prop="CostGMComm" label="成本-人工-总经理提成" width="170" align="center"> | |
| 145 | + <template slot-scope="scope"> | |
| 146 | + <span>{{ formatMoney(scope.row.CostGMComm) }}</span> | |
| 147 | + </template> | |
| 148 | + </el-table-column> | |
| 149 | + <el-table-column prop="CostOther1" label="成本-其他1" width="120" align="center"> | |
| 150 | + <template slot-scope="scope"> | |
| 151 | + <span>{{ formatMoney(scope.row.CostOther1) }}</span> | |
| 152 | + </template> | |
| 153 | + </el-table-column> | |
| 154 | + <el-table-column prop="CostOther2" label="成本-其他2" width="120" align="center"> | |
| 155 | + <template slot-scope="scope"> | |
| 156 | + <span>{{ formatMoney(scope.row.CostOther2) }}</span> | |
| 157 | + </template> | |
| 158 | + </el-table-column> | |
| 159 | + </el-table-column> | |
| 160 | + | |
| 161 | + <!-- 奖励 --> | |
| 162 | + <el-table-column label="奖励" align="center"> | |
| 163 | + <el-table-column prop="RewardTechDept" label="奖励-科技部" width="140" align="center"> | |
| 164 | + <template slot-scope="scope"> | |
| 165 | + <span>{{ formatMoney(scope.row.RewardTechDept) }}</span> | |
| 166 | + </template> | |
| 167 | + </el-table-column> | |
| 168 | + </el-table-column> | |
| 169 | + | |
| 170 | + <!-- 利润结果 --> | |
| 171 | + <el-table-column label="利润结果" align="center"> | |
| 172 | + <el-table-column prop="Profit" label="利润" width="120" align="center"> | |
| 173 | + <template slot-scope="scope"> | |
| 174 | + <span class="highlight">{{ formatMoney(scope.row.Profit) }}</span> | |
| 175 | + </template> | |
| 176 | + </el-table-column> | |
| 177 | + </el-table-column> | |
| 178 | + | |
| 179 | + <!-- 操作列 --> | |
| 180 | + <el-table-column label="操作" width="120" align="center" fixed="right"> | |
| 181 | + <template slot-scope="scope"> | |
| 182 | + <el-button | |
| 183 | + type="text" | |
| 184 | + size="mini" | |
| 185 | + icon="el-icon-view" | |
| 186 | + @click="showDetail(scope.row)" | |
| 187 | + > | |
| 188 | + 查看详情 | |
| 189 | + </el-button> | |
| 190 | + </template> | |
| 191 | + </el-table-column> | |
| 192 | + </NCC-table> | |
| 193 | + </div> | |
| 194 | + | |
| 195 | + <!-- 计算股份弹窗 --> | |
| 196 | + <el-dialog | |
| 197 | + title="计算科技部股份" | |
| 198 | + :visible="calculateDialogVisible" | |
| 199 | + width="500px" | |
| 200 | + :close-on-click-modal="false" | |
| 201 | + @close="handleCalculateDialogClose" | |
| 202 | + > | |
| 203 | + <el-form label-width="100px" label-position="right"> | |
| 204 | + <el-form-item label="统计月份" required> | |
| 205 | + <el-date-picker | |
| 206 | + v-model="calculateMonth" | |
| 207 | + type="month" | |
| 208 | + placeholder="请选择月份" | |
| 209 | + format="yyyyMM" | |
| 210 | + value-format="yyyyMM" | |
| 211 | + style="width: 100%" | |
| 212 | + /> | |
| 213 | + </el-form-item> | |
| 214 | + <el-form-item label="部门"> | |
| 215 | + <el-select | |
| 216 | + v-model="calculateDepartmentName" | |
| 217 | + placeholder="请选择部门(不选则计算所有部门)" | |
| 218 | + clearable | |
| 219 | + filterable | |
| 220 | + style="width: 100%" | |
| 221 | + > | |
| 222 | + <el-option label="科技一部" value="科技一部" /> | |
| 223 | + <el-option label="科技二部" value="科技二部" /> | |
| 224 | + </el-select> | |
| 225 | + </el-form-item> | |
| 226 | + </el-form> | |
| 227 | + <div slot="footer" class="dialog-footer"> | |
| 228 | + <el-button @click="handleCalculateDialogClose">取消</el-button> | |
| 229 | + <el-button | |
| 230 | + type="primary" | |
| 231 | + @click="handleCalculateConfirm" | |
| 232 | + :loading="calculateLoading" | |
| 233 | + > | |
| 234 | + 确定 | |
| 235 | + </el-button> | |
| 236 | + </div> | |
| 237 | + </el-dialog> | |
| 238 | + | |
| 239 | + <!-- 详情弹窗 --> | |
| 240 | + <tech-stock-detail-dialog | |
| 241 | + :visible="detailVisible" | |
| 242 | + :detail-data="currentDetailData" | |
| 243 | + @close="handleDetailClose" | |
| 244 | + /> | |
| 24 | 245 | </div> |
| 25 | 246 | </template> |
| 26 | 247 | |
| 27 | 248 | <script> |
| 249 | +import { getTechStockList, generateTechStock } from '@/api/extend/techStock' | |
| 250 | +import TechStockDetailDialog from './tech-stock-detail-dialog.vue' | |
| 251 | + | |
| 28 | 252 | export default { |
| 29 | 253 | name: 'TechStock', |
| 254 | + components: { | |
| 255 | + TechStockDetailDialog | |
| 256 | + }, | |
| 30 | 257 | data() { |
| 258 | + // 获取当前月份 | |
| 259 | + const getCurrentMonth = () => { | |
| 260 | + const now = new Date() | |
| 261 | + const year = now.getFullYear() | |
| 262 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 263 | + return `${year}${month}` | |
| 264 | + } | |
| 265 | + | |
| 31 | 266 | return { |
| 32 | - loading: false | |
| 267 | + loading: false, | |
| 268 | + calculateLoading: false, | |
| 269 | + exportLoading: false, | |
| 270 | + list: [], | |
| 271 | + calculateDialogVisible: false, | |
| 272 | + calculateMonth: getCurrentMonth(), | |
| 273 | + calculateDepartmentName: '', | |
| 274 | + detailVisible: false, | |
| 275 | + currentDetailData: null, | |
| 276 | + queryParams: { | |
| 277 | + statisticsMonth: getCurrentMonth(), // yyyyMM 格式 | |
| 278 | + departmentName: '' | |
| 279 | + } | |
| 33 | 280 | } |
| 34 | 281 | }, |
| 282 | + created() { | |
| 283 | + this.getList() | |
| 284 | + }, | |
| 35 | 285 | methods: { |
| 36 | - handleRefresh() { | |
| 286 | + // 获取列表数据 | |
| 287 | + async getList() { | |
| 37 | 288 | this.loading = true |
| 38 | - setTimeout(() => { | |
| 289 | + try { | |
| 290 | + const params = { | |
| 291 | + StatisticsMonth: this.queryParams.statisticsMonth || undefined, | |
| 292 | + DepartmentName: this.queryParams.departmentName || undefined | |
| 293 | + } | |
| 294 | + | |
| 295 | + const response = await getTechStockList(params) | |
| 296 | + | |
| 297 | + if (response.code === 200) { | |
| 298 | + this.list = response.data.data || [] | |
| 299 | + } else { | |
| 300 | + this.$message.error(response.msg || '获取数据失败') | |
| 301 | + } | |
| 302 | + } catch (error) { | |
| 303 | + console.error('获取科技部股份列表失败:', error) | |
| 304 | + this.$message.error('获取数据失败') | |
| 305 | + } finally { | |
| 39 | 306 | this.loading = false |
| 40 | - this.$message.success('刷新成功') | |
| 41 | - }, 500) | |
| 307 | + } | |
| 308 | + }, | |
| 309 | + | |
| 310 | + // 搜索 | |
| 311 | + handleQuery() { | |
| 312 | + this.getList() | |
| 313 | + }, | |
| 314 | + | |
| 315 | + // 重置搜索 | |
| 316 | + resetQuery() { | |
| 317 | + const getCurrentMonth = () => { | |
| 318 | + const now = new Date() | |
| 319 | + const year = now.getFullYear() | |
| 320 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 321 | + return `${year}${month}` | |
| 322 | + } | |
| 323 | + | |
| 324 | + this.queryParams = { | |
| 325 | + statisticsMonth: getCurrentMonth(), | |
| 326 | + departmentName: '' | |
| 327 | + } | |
| 328 | + this.getList() | |
| 329 | + }, | |
| 330 | + | |
| 331 | + // 显示计算股份弹窗 | |
| 332 | + showCalculateDialog() { | |
| 333 | + const getCurrentMonth = () => { | |
| 334 | + const now = new Date() | |
| 335 | + const year = now.getFullYear() | |
| 336 | + const month = String(now.getMonth() + 1).padStart(2, '0') | |
| 337 | + return `${year}${month}` | |
| 338 | + } | |
| 339 | + this.calculateMonth = getCurrentMonth() | |
| 340 | + this.calculateDepartmentName = '' | |
| 341 | + this.calculateDialogVisible = true | |
| 342 | + }, | |
| 343 | + | |
| 344 | + // 关闭计算股份弹窗 | |
| 345 | + handleCalculateDialogClose() { | |
| 346 | + this.calculateDialogVisible = false | |
| 347 | + }, | |
| 348 | + | |
| 349 | + // 确认计算股份 | |
| 350 | + async handleCalculateConfirm() { | |
| 351 | + if (!this.calculateMonth) { | |
| 352 | + this.$message.warning('请选择统计月份') | |
| 353 | + return | |
| 354 | + } | |
| 355 | + | |
| 356 | + this.calculateLoading = true | |
| 357 | + try { | |
| 358 | + const data = { | |
| 359 | + statisticsMonth: this.calculateMonth, | |
| 360 | + departmentName: this.calculateDepartmentName || undefined | |
| 361 | + } | |
| 362 | + | |
| 363 | + const response = await generateTechStock(data) | |
| 364 | + if (response.code === 200) { | |
| 365 | + this.$message.success('计算股份成功') | |
| 366 | + this.calculateDialogVisible = false | |
| 367 | + this.getList() | |
| 368 | + } else { | |
| 369 | + this.$message.error(response.msg || '计算股份失败') | |
| 370 | + } | |
| 371 | + } catch (error) { | |
| 372 | + console.error('计算股份失败:', error) | |
| 373 | + this.$message.error(error.message || '计算股份失败') | |
| 374 | + } finally { | |
| 375 | + this.calculateLoading = false | |
| 376 | + } | |
| 377 | + }, | |
| 378 | + | |
| 379 | + // 显示详情 | |
| 380 | + showDetail(row) { | |
| 381 | + this.currentDetailData = row | |
| 382 | + this.detailVisible = true | |
| 383 | + }, | |
| 384 | + | |
| 385 | + // 关闭详情弹窗 | |
| 386 | + handleDetailClose() { | |
| 387 | + this.detailVisible = false | |
| 388 | + this.currentDetailData = null | |
| 389 | + }, | |
| 390 | + | |
| 391 | + // 导出功能 | |
| 392 | + async handleExport() { | |
| 393 | + if (!this.list || this.list.length === 0) { | |
| 394 | + this.$message.warning('暂无数据可导出') | |
| 395 | + return | |
| 396 | + } | |
| 397 | + | |
| 398 | + this.exportLoading = true | |
| 399 | + try { | |
| 400 | + // 动态导入 xlsx 库 | |
| 401 | + const XLSX = await import('xlsx') | |
| 402 | + | |
| 403 | + // 构建表头(根据后端DTO字段的中文映射) | |
| 404 | + const headers = [ | |
| 405 | + '部门名称', | |
| 406 | + '统计月份', | |
| 407 | + '收入', | |
| 408 | + '成本-报销', | |
| 409 | + '成本-人工-老师底薪', | |
| 410 | + '成本-人工-手工费', | |
| 411 | + '成本-人工-开单提成', | |
| 412 | + '成本-人工-消耗提成', | |
| 413 | + '成本-人工-专家提成', | |
| 414 | + '成本-人工-加班', | |
| 415 | + '成本-人工-总经理底薪', | |
| 416 | + '成本-人工-总经理提成', | |
| 417 | + '奖励-科技部', | |
| 418 | + '成本-其他1', | |
| 419 | + '成本-其他2', | |
| 420 | + '利润' | |
| 421 | + ] | |
| 422 | + | |
| 423 | + // 构建数据行 | |
| 424 | + const dataRows = this.list.map(item => [ | |
| 425 | + item.DepartmentName || '无', | |
| 426 | + this.formatMonth(item.StatisticsMonth) || '无', | |
| 427 | + this.formatMoney(item.Income), | |
| 428 | + this.formatMoney(item.CostReimbursement), | |
| 429 | + this.formatMoney(item.CostTeacherBase), | |
| 430 | + this.formatMoney(item.CostTeacherManual), | |
| 431 | + this.formatMoney(item.CostTeacherBillingComm), | |
| 432 | + this.formatMoney(item.CostTeacherConsumeComm), | |
| 433 | + this.formatMoney(item.CostTeacherExpertComm), | |
| 434 | + this.formatMoney(item.CostTeacherOvertime), | |
| 435 | + this.formatMoney(item.CostGMBase), | |
| 436 | + this.formatMoney(item.CostGMComm), | |
| 437 | + this.formatMoney(item.RewardTechDept), | |
| 438 | + this.formatMoney(item.CostOther1), | |
| 439 | + this.formatMoney(item.CostOther2), | |
| 440 | + this.formatMoney(item.Profit) | |
| 441 | + ]) | |
| 442 | + | |
| 443 | + // 合并表头和数据 | |
| 444 | + const excelData = [headers, ...dataRows] | |
| 445 | + | |
| 446 | + // 创建工作表 | |
| 447 | + const ws = XLSX.utils.aoa_to_sheet(excelData) | |
| 448 | + | |
| 449 | + // 设置列宽 | |
| 450 | + const colWidths = headers.map(() => ({ wch: 15 })) | |
| 451 | + ws['!cols'] = colWidths | |
| 452 | + | |
| 453 | + // 创建工作簿 | |
| 454 | + const wb = XLSX.utils.book_new() | |
| 455 | + XLSX.utils.book_append_sheet(wb, ws, '科技部股份') | |
| 456 | + | |
| 457 | + // 生成文件名 | |
| 458 | + const now = new Date() | |
| 459 | + const timestamp = now.getFullYear() + | |
| 460 | + String(now.getMonth() + 1).padStart(2, '0') + | |
| 461 | + String(now.getDate()).padStart(2, '0') + | |
| 462 | + String(now.getHours()).padStart(2, '0') + | |
| 463 | + String(now.getMinutes()).padStart(2, '0') + | |
| 464 | + String(now.getSeconds()).padStart(2, '0') | |
| 465 | + const fileName = `科技部股份_${timestamp}.xlsx` | |
| 466 | + | |
| 467 | + // 导出文件 | |
| 468 | + XLSX.writeFile(wb, fileName) | |
| 469 | + | |
| 470 | + this.$message.success('导出成功') | |
| 471 | + } catch (error) { | |
| 472 | + console.error('导出失败:', error) | |
| 473 | + this.$message.error('导出失败,请重试') | |
| 474 | + } finally { | |
| 475 | + this.exportLoading = false | |
| 476 | + } | |
| 477 | + }, | |
| 478 | + | |
| 479 | + // 格式化金额 | |
| 480 | + formatMoney(value) { | |
| 481 | + if (value === null || value === undefined || value === '') { | |
| 482 | + return '0.00' | |
| 483 | + } | |
| 484 | + return Number(value).toFixed(2) | |
| 485 | + }, | |
| 486 | + | |
| 487 | + // 格式化月份 | |
| 488 | + formatMonth(value) { | |
| 489 | + if (!value || value.length !== 6) { | |
| 490 | + return value || '无' | |
| 491 | + } | |
| 492 | + const year = value.substring(0, 4) | |
| 493 | + const month = value.substring(4, 6) | |
| 494 | + return `${year}-${month}` | |
| 42 | 495 | } |
| 43 | 496 | } |
| 44 | 497 | } |
| ... | ... | @@ -81,12 +534,54 @@ export default { |
| 81 | 534 | } |
| 82 | 535 | } |
| 83 | 536 | |
| 84 | -.content-container { | |
| 537 | +.search-container { | |
| 538 | + margin-bottom: 20px; | |
| 85 | 539 | padding: 20px; |
| 86 | 540 | background: #fff; |
| 87 | 541 | border-radius: 8px; |
| 88 | 542 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| 89 | - min-height: 400px; | |
| 90 | 543 | } |
| 91 | -</style> | |
| 92 | 544 | |
| 545 | +.table-container { | |
| 546 | + margin-bottom: 20px; | |
| 547 | + padding: 20px; | |
| 548 | + background: #fff; | |
| 549 | + border-radius: 8px; | |
| 550 | + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| 551 | +} | |
| 552 | + | |
| 553 | +.department-name { | |
| 554 | + display: flex; | |
| 555 | + align-items: center; | |
| 556 | + gap: 6px; | |
| 557 | + | |
| 558 | + .department-icon { | |
| 559 | + color: #409EFF; | |
| 560 | + font-size: 16px; | |
| 561 | + } | |
| 562 | +} | |
| 563 | + | |
| 564 | +.highlight { | |
| 565 | + color: #409EFF; | |
| 566 | + font-weight: 600; | |
| 567 | +} | |
| 568 | + | |
| 569 | +// 表格样式优化 | |
| 570 | +::v-deep .el-table { | |
| 571 | + .el-table__header-wrapper { | |
| 572 | + th { | |
| 573 | + background-color: #f5f7fa; | |
| 574 | + color: #606266; | |
| 575 | + font-weight: 600; | |
| 576 | + } | |
| 577 | + } | |
| 578 | + | |
| 579 | + .el-table__body-wrapper { | |
| 580 | + .el-table__row { | |
| 581 | + &:hover { | |
| 582 | + background-color: #f5f7fa; | |
| 583 | + } | |
| 584 | + } | |
| 585 | + } | |
| 586 | +} | |
| 587 | +</style> | ... | ... |