Commit 9864a8182636946663cc930a1e7b24f218e8c8d2
1 parent
28404662
feat: 优化拓客管理功能
- 新增 TkjlbExportModel DTO 类,将导出模型从服务层分离到 DTO 层 - 修复拓客管理导出功能的下载地址500错误 - 优化拓客管理列表页面: * 将活动编号搜索改为下拉框选择 * 调整列宽度,拓客编号列加宽,备注列移除宽度限制 * 移除编辑、删除、批量删除按钮 * 优化表格样式和用户体验 - 简化导出功能,固定导出字段,支持活动编号和截止时间筛选 - 修复开单记录表导出功能,添加中文名称显示 - 创建临时文件目录以支持文件导出功能
Showing
7 changed files
with
479 additions
and
178 deletions
antis-ncc-admin/src/views/lqTkjlb/ExportBox.vue
| 1 | 1 | <template> |
| 2 | - <el-dialog title="导出数据" :close-on-click-modal="false" :visible.sync="visible" | |
| 3 | - class="NCC-dialog NCC-dialog_center" lock-scroll width="600px"> | |
| 4 | - <el-form label-position="top" label-width="80px"> | |
| 5 | - <el-form-item label="数据选择"> | |
| 6 | - <el-radio-group v-model="type"> | |
| 7 | - <el-radio :label="0">当前页面数据</el-radio> | |
| 8 | - <el-radio :label="1">全部页面数据</el-radio> | |
| 9 | - </el-radio-group> | |
| 2 | + <el-dialog title="导出拓客数据" :close-on-click-modal="false" :visible.sync="visible" | |
| 3 | + class="NCC-dialog NCC-dialog_center" lock-scroll width="500px"> | |
| 4 | + <el-form label-position="right" label-width="100px"> | |
| 5 | + <el-form-item label="活动编号"> | |
| 6 | + <el-select v-model="exportParams.eventId" placeholder="请选择活动编号(可选)" clearable filterable :loading="eventListLoading"> | |
| 7 | + <el-option | |
| 8 | + v-for="event in eventList" | |
| 9 | + :key="event.id" | |
| 10 | + :label="`${event.eventNumber} - ${event.eventName}`" | |
| 11 | + :value="event.id"> | |
| 12 | + </el-option> | |
| 13 | + </el-select> | |
| 14 | + <div class="form-tip">留空则导出所有活动的数据</div> | |
| 10 | 15 | </el-form-item> |
| 11 | - <el-form-item label="导出字段"> | |
| 12 | - <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" | |
| 13 | - @change="handleCheckAllChange">全选</el-checkbox> | |
| 14 | - <el-checkbox-group v-model="columns" @change="handleCheckedChange"> | |
| 15 | - <el-checkbox v-for="item in columnList" :label="item.prop" :key="item.prop"> | |
| 16 | - {{item.label}} | |
| 17 | - </el-checkbox> | |
| 18 | - </el-checkbox-group> | |
| 16 | + <el-form-item label="截止时间"> | |
| 17 | + <el-date-picker | |
| 18 | + v-model="exportParams.endTime" | |
| 19 | + type="datetime" | |
| 20 | + value-format="yyyy-MM-dd HH:mm:ss" | |
| 21 | + format="yyyy-MM-dd HH:mm:ss" | |
| 22 | + placeholder="请选择截止时间(可选)" | |
| 23 | + clearable> | |
| 24 | + </el-date-picker> | |
| 25 | + <div class="form-tip">留空则导出所有时间的数据</div> | |
| 26 | + </el-form-item> | |
| 27 | + <el-form-item label="导出说明"> | |
| 28 | + <div class="export-info"> | |
| 29 | + <p>• 导出包含15个字段:拓客编号、拓客时间、拓客人员、顾客姓名、电话号码、购买张数、支付方式、是否加微信、备注、门店名称、活动名称等</p> | |
| 30 | + <p>• 所有字段都会显示中文名称,无需手动选择</p> | |
| 31 | + <p>• 支持从下拉框选择活动编号,或按截止时间进行筛选</p> | |
| 32 | + <p>• 活动编号显示格式:编号 - 活动名称</p> | |
| 33 | + </div> | |
| 19 | 34 | </el-form-item> |
| 20 | 35 | </el-form> |
| 21 | 36 | <span slot="footer" class="dialog-footer"> |
| 22 | 37 | <el-button @click="visible=false">取 消</el-button> |
| 23 | - <el-button type="primary" @click="downLoad">导 出</el-button> | |
| 38 | + <el-button type="primary" @click="downLoad" :loading="btnLoading">导 出</el-button> | |
| 24 | 39 | </span> |
| 25 | 40 | </el-dialog> |
| 26 | 41 | </template> |
| 27 | 42 | |
| 28 | 43 | <script> |
| 44 | +import { getLqEventList } from '@/api/extend/lqevent' | |
| 45 | + | |
| 29 | 46 | export default { |
| 30 | 47 | data() { |
| 31 | 48 | return { |
| 32 | 49 | visible: false, |
| 33 | 50 | btnLoading: false, |
| 34 | - type: 0, | |
| 35 | - columns: [], | |
| 36 | - checkAll: true, | |
| 37 | - isIndeterminate: false, | |
| 38 | - columnList: [] | |
| 51 | + eventList: [], | |
| 52 | + eventListLoading: false, | |
| 53 | + exportParams: { | |
| 54 | + eventId: '', | |
| 55 | + endTime: '' | |
| 56 | + } | |
| 39 | 57 | } |
| 40 | 58 | }, |
| 41 | 59 | methods: { |
| 42 | - init(columnList) { | |
| 60 | + init() { | |
| 43 | 61 | this.visible = true |
| 44 | - this.columnList = columnList | |
| 45 | - this.columns = columnList.map(o => o.prop) | |
| 46 | - }, | |
| 47 | - handleCheckAllChange(val) { | |
| 48 | - this.columns = val ? this.columnList.map(o => o.prop) : []; | |
| 49 | - this.isIndeterminate = false; | |
| 62 | + // 重置参数 | |
| 63 | + this.exportParams = { | |
| 64 | + eventId: '', | |
| 65 | + endTime: '' | |
| 66 | + } | |
| 67 | + // 获取活动列表 | |
| 68 | + this.getEventList() | |
| 50 | 69 | }, |
| 51 | - handleCheckedChange(value) { | |
| 52 | - let checkedCount = value.length; | |
| 53 | - this.checkAll = checkedCount === this.columnList.length; | |
| 54 | - this.isIndeterminate = checkedCount > 0 && checkedCount < this.columnList.length; | |
| 70 | + // 获取拓客活动列表 | |
| 71 | + async getEventList() { | |
| 72 | + this.eventListLoading = true | |
| 73 | + try { | |
| 74 | + const response = await getLqEventList({ | |
| 75 | + currentPage: 1, | |
| 76 | + pageSize: 1000 // 获取所有活动 | |
| 77 | + }) | |
| 78 | + if (response.code === 200 && response.data && response.data.list) { | |
| 79 | + this.eventList = response.data.list.map(event => ({ | |
| 80 | + id: event.id, | |
| 81 | + eventNumber: event.eventNumber, | |
| 82 | + eventName: event.eventName | |
| 83 | + })) | |
| 84 | + } else { | |
| 85 | + this.eventList = [] | |
| 86 | + } | |
| 87 | + } catch (error) { | |
| 88 | + console.error('获取活动列表失败:', error) | |
| 89 | + this.eventList = [] | |
| 90 | + this.$message({ | |
| 91 | + type: 'warning', | |
| 92 | + message: '获取活动列表失败,请手动输入活动编号' | |
| 93 | + }) | |
| 94 | + } finally { | |
| 95 | + this.eventListLoading = false | |
| 96 | + } | |
| 55 | 97 | }, |
| 56 | 98 | downLoad() { |
| 57 | - this.$emit('download', { dataType: this.type, selectKey: this.columns.join(',') }) | |
| 99 | + this.btnLoading = true | |
| 100 | + // 发送简化的参数 | |
| 101 | + this.$emit('download', { | |
| 102 | + eventId: this.exportParams.eventId || null, | |
| 103 | + endTime: this.exportParams.endTime || null | |
| 104 | + }) | |
| 105 | + // 延迟重置loading状态 | |
| 106 | + setTimeout(() => { | |
| 107 | + this.btnLoading = false | |
| 108 | + }, 1000) | |
| 58 | 109 | } |
| 59 | 110 | } |
| 60 | 111 | } |
| ... | ... | @@ -63,4 +114,32 @@ export default { |
| 63 | 114 | >>> .el-dialog__body { |
| 64 | 115 | padding: 20px !important; |
| 65 | 116 | } |
| 117 | + | |
| 118 | +.form-tip { | |
| 119 | + font-size: 12px; | |
| 120 | + color: #909399; | |
| 121 | + margin-top: 5px; | |
| 122 | +} | |
| 123 | + | |
| 124 | +.export-info { | |
| 125 | + background-color: #f5f7fa; | |
| 126 | + padding: 15px; | |
| 127 | + border-radius: 4px; | |
| 128 | + border-left: 4px solid #409eff; | |
| 129 | + | |
| 130 | + p { | |
| 131 | + margin: 5px 0; | |
| 132 | + font-size: 13px; | |
| 133 | + color: #606266; | |
| 134 | + line-height: 1.5; | |
| 135 | + } | |
| 136 | +} | |
| 137 | + | |
| 138 | +.el-form-item { | |
| 139 | + margin-bottom: 20px; | |
| 140 | +} | |
| 141 | + | |
| 142 | +.dialog-footer { | |
| 143 | + text-align: right; | |
| 144 | +} | |
| 66 | 145 | </style> |
| 67 | 146 | \ No newline at end of file | ... | ... |
antis-ncc-admin/src/views/lqTkjlb/index.vue
| ... | ... | @@ -12,7 +12,14 @@ |
| 12 | 12 | </el-col> |
| 13 | 13 | <el-col :span="6"> |
| 14 | 14 | <el-form-item label="拓客活动"> |
| 15 | - <el-input v-model="query.eventId" placeholder="拓客活动" clearable /> | |
| 15 | + <el-select v-model="query.eventId" placeholder="请选择拓客活动" clearable filterable :loading="eventListLoading"> | |
| 16 | + <el-option | |
| 17 | + v-for="event in eventList" | |
| 18 | + :key="event.id" | |
| 19 | + :label="`${event.eventNumber} - ${event.eventName}`" | |
| 20 | + :value="event.id"> | |
| 21 | + </el-option> | |
| 22 | + </el-select> | |
| 16 | 23 | </el-form-item> |
| 17 | 24 | </el-col> |
| 18 | 25 | <el-col :span="6"> |
| ... | ... | @@ -20,6 +27,11 @@ |
| 20 | 27 | <userSelect v-model="query.expansionUserId" placeholder="请选择拓客人员" /> |
| 21 | 28 | </el-form-item> |
| 22 | 29 | </el-col> |
| 30 | + <el-col :span="6"> | |
| 31 | + <el-form-item label="所属门店"> | |
| 32 | + <el-input v-model="query.storeId" placeholder="请输入门店名称" clearable /> | |
| 33 | + </el-form-item> | |
| 34 | + </el-col> | |
| 23 | 35 | |
| 24 | 36 | <template v-if="showAll"> |
| 25 | 37 | <el-col :span="6"> |
| ... | ... | @@ -53,6 +65,11 @@ |
| 53 | 65 | </el-select> |
| 54 | 66 | </el-form-item> |
| 55 | 67 | </el-col> |
| 68 | + <el-col :span="6"> | |
| 69 | + <el-form-item label="所属战队"> | |
| 70 | + <el-input v-model="query.teamName" placeholder="请输入战队名称" clearable /> | |
| 71 | + </el-form-item> | |
| 72 | + </el-col> | |
| 56 | 73 | </template> |
| 57 | 74 | <el-col :span="6"> |
| 58 | 75 | <el-form-item> |
| ... | ... | @@ -67,9 +84,7 @@ |
| 67 | 84 | <div class="NCC-common-layout-main NCC-flex-main"> |
| 68 | 85 | <div class="NCC-common-head"> |
| 69 | 86 | <div> |
| 70 | - <el-button type="primary" icon="el-icon-plus" @click="addOrUpdateHandle()">新增</el-button> | |
| 71 | 87 | <el-button type="text" icon="el-icon-download" @click="exportData()">导出</el-button> |
| 72 | - <el-button type="text" icon="el-icon-delete" @click="handleBatchRemoveDel()">批量删除</el-button> | |
| 73 | 88 | <el-button type="success" icon="el-icon-s-data" @click="goToReport()">拓客报表</el-button> |
| 74 | 89 | </div> |
| 75 | 90 | <div class="NCC-common-head-right"> |
| ... | ... | @@ -79,32 +94,28 @@ |
| 79 | 94 | <screenfull isContainer /> |
| 80 | 95 | </div> |
| 81 | 96 | </div> |
| 82 | - <NCC-table v-loading="listLoading" :data="list" has-c @selection-change="handleSelectionChange"> | |
| 83 | - <el-table-column prop="eventName" label="拓客活动" align="left" /> | |
| 84 | - <el-table-column prop="expansionUserId" label="拓客人员" align="left" /> | |
| 85 | - <el-table-column prop="expansionTime" label="拓客时间" align="left" :formatter="ncc.tableDateFormat" /> | |
| 86 | - <el-table-column prop="customerName" label="顾客姓名" align="left" /> | |
| 87 | - <el-table-column prop="customerPhone" label="电话号码" align="left" /> | |
| 88 | - <el-table-column prop="buyNumber" label="购买张数" align="left" /> | |
| 89 | - <el-table-column label="支付方式" prop="paymentMethod" align="left"> | |
| 97 | + <NCC-table v-loading="listLoading" :data="list"> | |
| 98 | + <el-table-column prop="id" label="拓客编号" align="left" width="160" show-overflow-tooltip /> | |
| 99 | + <el-table-column prop="eventName" label="拓客活动" align="left" width="150" show-overflow-tooltip /> | |
| 100 | + <el-table-column prop="expansionUserName" label="拓客人员" align="left" width="100" show-overflow-tooltip /> | |
| 101 | + <el-table-column prop="storeName" label="所属门店" align="left" width="120" show-overflow-tooltip /> | |
| 102 | + <el-table-column prop="expansionTime" label="拓客时间" align="left" width="150" :formatter="ncc.tableDateFormat" /> | |
| 103 | + <el-table-column prop="customerName" label="顾客姓名" align="left" width="100" show-overflow-tooltip /> | |
| 104 | + <el-table-column prop="customerPhone" label="电话号码" align="left" width="120" show-overflow-tooltip /> | |
| 105 | + <el-table-column prop="buyNumber" label="购买张数" align="center" width="80" /> | |
| 106 | + <el-table-column label="支付方式" prop="paymentMethod" align="left" width="100"> | |
| 90 | 107 | <template slot-scope="scope">{{ scope.row.paymentMethod | dynamicText(zffsOptions) }}</template> |
| 91 | 108 | </el-table-column> |
| 92 | - <el-table-column label="是否加微信" prop="isAddWeChat" align="left"> | |
| 109 | + <el-table-column label="是否加微信" prop="isAddWeChat" align="center" width="100"> | |
| 93 | 110 | <template slot-scope="scope">{{ scope.row.isAddWeChat | dynamicText(sfjwxOptions) }}</template> |
| 94 | 111 | </el-table-column> |
| 95 | - <el-table-column prop="remarks" label="备注" align="left" /> | |
| 96 | - <el-table-column label="操作" fixed="right" width="100"> | |
| 97 | - <template slot-scope="scope"> | |
| 98 | - <el-button type="text" @click="addOrUpdateHandle(scope.row.id)">编辑</el-button> | |
| 99 | - <el-button type="text" @click="handleDel(scope.row.id)" class="NCC-table-delBtn">删除</el-button> | |
| 100 | - </template> | |
| 101 | - </el-table-column> | |
| 112 | + <el-table-column prop="teamName" label="所属战队" align="left" width="100" show-overflow-tooltip /> | |
| 113 | + <el-table-column prop="remarks" label="备注" align="left" show-overflow-tooltip /> | |
| 102 | 114 | </NCC-table> |
| 103 | 115 | <pagination :total="total" :page.sync="listQuery.currentPage" :limit.sync="listQuery.pageSize" |
| 104 | 116 | @pagination="initData" /> |
| 105 | 117 | </div> |
| 106 | 118 | </div> |
| 107 | - <NCC-Form v-if="formVisible" ref="NCCForm" @refresh="refresh" /> | |
| 108 | 119 | <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" /> |
| 109 | 120 | </div> |
| 110 | 121 | </template> |
| ... | ... | @@ -113,19 +124,20 @@ |
| 113 | 124 | import { |
| 114 | 125 | getDictionaryDataSelector |
| 115 | 126 | } from '@/api/systemData/dictionary' |
| 116 | - import NCCForm from './Form' | |
| 117 | 127 | import ExportBox from './ExportBox' |
| 118 | 128 | import { |
| 119 | 129 | previewDataInterface |
| 120 | 130 | } from '@/api/systemData/dataInterface' |
| 131 | + import { getLqEventList } from '@/api/extend/lqevent' | |
| 121 | 132 | export default { |
| 122 | 133 | components: { |
| 123 | - NCCForm, | |
| 124 | 134 | ExportBox |
| 125 | 135 | }, |
| 126 | 136 | data() { |
| 127 | 137 | return { |
| 128 | 138 | showAll: false, |
| 139 | + eventList: [], | |
| 140 | + eventListLoading: false, | |
| 129 | 141 | query: { |
| 130 | 142 | id: undefined, |
| 131 | 143 | expansionUserId: undefined, |
| ... | ... | @@ -137,12 +149,11 @@ |
| 137 | 149 | isAddWeChat: undefined, |
| 138 | 150 | remarks: undefined, |
| 139 | 151 | eventId: undefined, |
| 140 | - ssmd: undefined, | |
| 141 | - sszd: undefined, | |
| 152 | + storeId: undefined, | |
| 153 | + teamName: undefined, | |
| 142 | 154 | }, |
| 143 | 155 | list: [], |
| 144 | 156 | listLoading: true, |
| 145 | - multipleSelection: [], | |
| 146 | 157 | total: 0, |
| 147 | 158 | listQuery: { |
| 148 | 159 | currentPage: 1, |
| ... | ... | @@ -150,17 +161,24 @@ |
| 150 | 161 | sort: "desc", |
| 151 | 162 | sidx: "", |
| 152 | 163 | }, |
| 153 | - formVisible: false, | |
| 154 | 164 | exportBoxVisible: false, |
| 155 | 165 | columnList: [{ |
| 156 | 166 | prop: 'id', |
| 157 | 167 | label: '拓客编号' |
| 158 | 168 | }, |
| 159 | 169 | { |
| 160 | - prop: 'expansionUserId', | |
| 170 | + prop: 'eventName', | |
| 171 | + label: '拓客活动' | |
| 172 | + }, | |
| 173 | + { | |
| 174 | + prop: 'expansionUserName', | |
| 161 | 175 | label: '拓客人员' |
| 162 | 176 | }, |
| 163 | 177 | { |
| 178 | + prop: 'storeName', | |
| 179 | + label: '所属门店' | |
| 180 | + }, | |
| 181 | + { | |
| 164 | 182 | prop: 'expansionTime', |
| 165 | 183 | label: '拓客时间' |
| 166 | 184 | }, |
| ... | ... | @@ -185,20 +203,12 @@ |
| 185 | 203 | label: '是否加微信' |
| 186 | 204 | }, |
| 187 | 205 | { |
| 188 | - prop: 'remarks', | |
| 189 | - label: '备注' | |
| 190 | - }, | |
| 191 | - { | |
| 192 | - prop: 'eventId', | |
| 193 | - label: '拓客活动' | |
| 194 | - }, | |
| 195 | - { | |
| 196 | - prop: 'ssmd', | |
| 197 | - label: '所属门店' | |
| 206 | + prop: 'teamName', | |
| 207 | + label: '所属战队' | |
| 198 | 208 | }, |
| 199 | 209 | { |
| 200 | - prop: 'sszd', | |
| 201 | - label: '所属战队' | |
| 210 | + prop: 'remarks', | |
| 211 | + label: '备注' | |
| 202 | 212 | }, |
| 203 | 213 | ], |
| 204 | 214 | zffsOptions: [{ |
| ... | ... | @@ -225,9 +235,34 @@ |
| 225 | 235 | }, |
| 226 | 236 | computed: {}, |
| 227 | 237 | created() { |
| 238 | + this.getEventList() | |
| 228 | 239 | this.initData() |
| 229 | 240 | }, |
| 230 | 241 | methods: { |
| 242 | + // 获取拓客活动列表 | |
| 243 | + async getEventList() { | |
| 244 | + this.eventListLoading = true | |
| 245 | + try { | |
| 246 | + const response = await getLqEventList({ | |
| 247 | + currentPage: 1, | |
| 248 | + pageSize: 1000 // 获取所有活动 | |
| 249 | + }) | |
| 250 | + if (response.code === 200 && response.data && response.data.list) { | |
| 251 | + this.eventList = response.data.list.map(event => ({ | |
| 252 | + id: event.id, | |
| 253 | + eventNumber: event.eventNumber, | |
| 254 | + eventName: event.eventName | |
| 255 | + })) | |
| 256 | + } else { | |
| 257 | + this.eventList = [] | |
| 258 | + } | |
| 259 | + } catch (error) { | |
| 260 | + console.error('获取活动列表失败:', error) | |
| 261 | + this.eventList = [] | |
| 262 | + } finally { | |
| 263 | + this.eventListLoading = false | |
| 264 | + } | |
| 265 | + }, | |
| 231 | 266 | initData() { |
| 232 | 267 | this.listLoading = true; |
| 233 | 268 | let _query = { |
| ... | ... | @@ -252,81 +287,43 @@ |
| 252 | 287 | this.listLoading = false |
| 253 | 288 | }) |
| 254 | 289 | }, |
| 255 | - handleDel(id) { | |
| 256 | - this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', { | |
| 257 | - type: 'warning' | |
| 258 | - }).then(() => { | |
| 259 | - request({ | |
| 260 | - url: `/api/Extend/LqTkjlb/${id}`, | |
| 261 | - method: 'DELETE' | |
| 262 | - }).then(res => { | |
| 263 | - this.$message({ | |
| 264 | - type: 'success', | |
| 265 | - message: res.msg, | |
| 266 | - onClose: () => { | |
| 267 | - this.initData() | |
| 268 | - } | |
| 269 | - }); | |
| 270 | - }) | |
| 271 | - }).catch(() => {}); | |
| 272 | - }, | |
| 273 | - handleSelectionChange(val) { | |
| 274 | - const res = val.map(item => item.id) | |
| 275 | - this.multipleSelection = res | |
| 276 | - }, | |
| 277 | - handleBatchRemoveDel() { | |
| 278 | - if (!this.multipleSelection.length) { | |
| 279 | - this.$message({ | |
| 280 | - type: 'error', | |
| 281 | - message: '请选择一条数据', | |
| 282 | - duration: 1500, | |
| 283 | - }) | |
| 284 | - return | |
| 285 | - } | |
| 286 | - const ids = this.multipleSelection | |
| 287 | - this.$confirm('您确定要删除这些数据吗, 是否继续?', '提示', { | |
| 288 | - type: 'warning' | |
| 289 | - }).then(() => { | |
| 290 | - request({ | |
| 291 | - url: `/api/Extend/LqTkjlb/batchRemove`, | |
| 292 | - method: 'POST', | |
| 293 | - data: ids, | |
| 294 | - }).then(res => { | |
| 295 | - this.$message({ | |
| 296 | - type: 'success', | |
| 297 | - message: res.msg, | |
| 298 | - onClose: () => { | |
| 299 | - this.initData() | |
| 300 | - } | |
| 301 | - }); | |
| 302 | - }) | |
| 303 | - }).catch(() => {}) | |
| 304 | - }, | |
| 305 | - addOrUpdateHandle(id, isDetail) { | |
| 306 | - this.formVisible = true | |
| 307 | - this.$nextTick(() => { | |
| 308 | - this.$refs.NCCForm.init(id, isDetail) | |
| 309 | - }) | |
| 310 | - }, | |
| 311 | 290 | exportData() { |
| 312 | 291 | this.exportBoxVisible = true |
| 313 | 292 | this.$nextTick(() => { |
| 314 | - this.$refs.ExportBox.init(this.columnList) | |
| 293 | + this.$refs.ExportBox.init() | |
| 315 | 294 | }) |
| 316 | 295 | }, |
| 317 | 296 | download(data) { |
| 297 | + // 使用简化的参数 | |
| 318 | 298 | let query = { |
| 319 | - ...data, | |
| 320 | - ...this.listQuery, | |
| 321 | - ...this.query | |
| 299 | + eventId: data.eventId, | |
| 300 | + endTime: data.endTime | |
| 322 | 301 | } |
| 302 | + | |
| 323 | 303 | request({ |
| 324 | 304 | url: `/api/Extend/LqTkjlb/Actions/Export`, |
| 325 | 305 | method: 'GET', |
| 326 | 306 | data: query |
| 327 | 307 | }).then(res => { |
| 328 | - if (!res.data.url) return | |
| 329 | - window.location.href = this.define.comUrl + res.data.url | |
| 308 | + if (res.data.url) { | |
| 309 | + window.location.href = this.define.comUrl + res.data.url | |
| 310 | + this.$message({ | |
| 311 | + type: 'success', | |
| 312 | + message: '导出成功!' | |
| 313 | + }) | |
| 314 | + } else if (res.data.message) { | |
| 315 | + this.$message({ | |
| 316 | + type: 'error', | |
| 317 | + message: res.data.message | |
| 318 | + }) | |
| 319 | + } | |
| 320 | + this.$refs.ExportBox.visible = false | |
| 321 | + this.exportBoxVisible = false | |
| 322 | + }).catch(error => { | |
| 323 | + this.$message({ | |
| 324 | + type: 'error', | |
| 325 | + message: '导出失败:' + (error.message || '未知错误') | |
| 326 | + }) | |
| 330 | 327 | this.$refs.ExportBox.visible = false |
| 331 | 328 | this.exportBoxVisible = false |
| 332 | 329 | }) |
| ... | ... | @@ -340,10 +337,6 @@ |
| 340 | 337 | } |
| 341 | 338 | this.initData() |
| 342 | 339 | }, |
| 343 | - refresh(isrRefresh) { | |
| 344 | - this.formVisible = false | |
| 345 | - if (isrRefresh) this.reset() | |
| 346 | - }, | |
| 347 | 340 | reset() { |
| 348 | 341 | for (let key in this.query) { |
| 349 | 342 | this.query[key] = undefined |
| ... | ... | @@ -364,3 +357,79 @@ |
| 364 | 357 | } |
| 365 | 358 | } |
| 366 | 359 | </script> |
| 360 | + | |
| 361 | +<style lang="scss" scoped> | |
| 362 | +.NCC-common-layout { | |
| 363 | + .NCC-table { | |
| 364 | + .el-table { | |
| 365 | + .el-table__header { | |
| 366 | + th { | |
| 367 | + background-color: #f5f7fa; | |
| 368 | + color: #606266; | |
| 369 | + font-weight: 600; | |
| 370 | + } | |
| 371 | + } | |
| 372 | + | |
| 373 | + .el-table__body { | |
| 374 | + tr:hover { | |
| 375 | + background-color: #f5f7fa; | |
| 376 | + } | |
| 377 | + } | |
| 378 | + } | |
| 379 | + } | |
| 380 | + | |
| 381 | + .NCC-common-search-box { | |
| 382 | + .el-form-item { | |
| 383 | + margin-bottom: 18px; | |
| 384 | + | |
| 385 | + .el-form-item__label { | |
| 386 | + font-weight: 500; | |
| 387 | + color: #606266; | |
| 388 | + } | |
| 389 | + } | |
| 390 | + } | |
| 391 | + | |
| 392 | + .NCC-common-head { | |
| 393 | + .el-button { | |
| 394 | + margin-right: 8px; | |
| 395 | + | |
| 396 | + &.el-button--primary { | |
| 397 | + background-color: #409eff; | |
| 398 | + border-color: #409eff; | |
| 399 | + } | |
| 400 | + | |
| 401 | + &.el-button--text { | |
| 402 | + color: #409eff; | |
| 403 | + | |
| 404 | + &:hover { | |
| 405 | + color: #66b1ff; | |
| 406 | + } | |
| 407 | + } | |
| 408 | + } | |
| 409 | + } | |
| 410 | +} | |
| 411 | + | |
| 412 | +// 表格列宽度优化 | |
| 413 | +.el-table { | |
| 414 | + .el-table__header-wrapper { | |
| 415 | + th { | |
| 416 | + padding: 12px 0; | |
| 417 | + } | |
| 418 | + } | |
| 419 | + | |
| 420 | + .el-table__body-wrapper { | |
| 421 | + td { | |
| 422 | + padding: 12px 0; | |
| 423 | + } | |
| 424 | + } | |
| 425 | +} | |
| 426 | + | |
| 427 | +// 操作按钮样式 | |
| 428 | +.NCC-table-delBtn { | |
| 429 | + color: #f56c6c !important; | |
| 430 | + | |
| 431 | + &:hover { | |
| 432 | + color: #f78989 !important; | |
| 433 | + } | |
| 434 | +} | |
| 435 | +</style> | ... | ... |
netcore/src/Application/NCC.API/appsettings.json
| ... | ... | @@ -184,7 +184,7 @@ |
| 184 | 184 | "NCC_App": { |
| 185 | 185 | "CodeAreasName": "SubDev,Food,Extend,test", |
| 186 | 186 | //系统文件路径(末尾必须带斜杆) |
| 187 | - "SystemPath": "C:\\web\\NCC\\uu-resources\\", | |
| 187 | + "SystemPath": "Files/", | |
| 188 | 188 | //微信公众号允许上传文件类型 |
| 189 | 189 | "MPUploadFileType": "bmp,png,jpeg,jpg,gif,mp3,wma,wav,amr,mp4", |
| 190 | 190 | //微信允许上传文件类型 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/LqTkjlbListOutput.cs
| ... | ... | @@ -23,6 +23,16 @@ namespace NCC.Extend.Entitys.Dto.LqTkjlb |
| 23 | 23 | public string expansionUserId { get; set; } |
| 24 | 24 | |
| 25 | 25 | /// <summary> |
| 26 | + /// 所属部门ID | |
| 27 | + /// </summary> | |
| 28 | + public string depId { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 所属部门名称 | |
| 32 | + /// </summary> | |
| 33 | + public string depName { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 26 | 36 | /// 拓客人员 |
| 27 | 37 | /// </summary> |
| 28 | 38 | public string expansionUserName { get; set; } | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqTkjlb/TkjlbExportModel.cs
0 → 100644
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace NCC.Extend.Entitys.Dto.LqTkjlb | |
| 4 | +{ | |
| 5 | + /// <summary> | |
| 6 | + /// 拓客管理导出数据模型 | |
| 7 | + /// </summary> | |
| 8 | + public class TkjlbExportModel | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 拓客编号 | |
| 12 | + /// </summary> | |
| 13 | + public string id { get; set; } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 拓客时间 | |
| 17 | + /// </summary> | |
| 18 | + public DateTime expansionTime { get; set; } | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 拓客人员ID | |
| 22 | + /// </summary> | |
| 23 | + public string expansionUserId { get; set; } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 拓客人员姓名 | |
| 27 | + /// </summary> | |
| 28 | + public string expansionUserName { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 顾客姓名 | |
| 32 | + /// </summary> | |
| 33 | + public string customerName { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 顾客电话 | |
| 37 | + /// </summary> | |
| 38 | + public string customerPhone { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 购买张数 | |
| 42 | + /// </summary> | |
| 43 | + public int buyNumber { get; set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 支付方式 | |
| 47 | + /// </summary> | |
| 48 | + public string paymentMethod { get; set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 是否加微信 | |
| 52 | + /// </summary> | |
| 53 | + public string isAddWeChat { get; set; } | |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 备注 | |
| 57 | + /// </summary> | |
| 58 | + public string remarks { get; set; } | |
| 59 | + | |
| 60 | + /// <summary> | |
| 61 | + /// 门店ID | |
| 62 | + /// </summary> | |
| 63 | + public string storeId { get; set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 门店名称 | |
| 67 | + /// </summary> | |
| 68 | + public string storeName { get; set; } | |
| 69 | + | |
| 70 | + /// <summary> | |
| 71 | + /// 战队名称 | |
| 72 | + /// </summary> | |
| 73 | + public string teamName { get; set; } | |
| 74 | + | |
| 75 | + /// <summary> | |
| 76 | + /// 活动ID | |
| 77 | + /// </summary> | |
| 78 | + public string eventId { get; set; } | |
| 79 | + | |
| 80 | + /// <summary> | |
| 81 | + /// 活动名称 | |
| 82 | + /// </summary> | |
| 83 | + public string eventName { get; set; } | |
| 84 | + } | |
| 85 | +} | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
| ... | ... | @@ -351,11 +351,6 @@ namespace NCC.Extend.LqKdKdjlb |
| 351 | 351 | } |
| 352 | 352 | } |
| 353 | 353 | |
| 354 | - // 处理健康师姓名,去除最后的逗号并赋值给实体 | |
| 355 | - if (!string.IsNullOrEmpty(HealthInstructorNames)) | |
| 356 | - { | |
| 357 | - HealthInstructorNames = HealthInstructorNames.TrimEnd(','); | |
| 358 | - } | |
| 359 | 354 | |
| 360 | 355 | //通过会员id查询会员信息 |
| 361 | 356 | var memberInfo = await _db.Queryable<LqKhxxEntity>().Where(u => u.Id == entity.Kdhy).FirstAsync(); | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqTkjlbService.cs
| ... | ... | @@ -133,6 +133,8 @@ namespace NCC.Extend.LqTkjlb |
| 133 | 133 | teamName = it.TeamName, |
| 134 | 134 | eventId = it.EventId, |
| 135 | 135 | eventName = SqlFunc.Subqueryable<LqEventEntity>().Where(u => u.Id == it.EventId).Select(u => u.EventName), |
| 136 | + depId = it.DepId, | |
| 137 | + depName = SqlFunc.Subqueryable<OrganizeEntity>().Where(u => u.Id == it.DepId).Select(u => u.FullName), | |
| 136 | 138 | }) |
| 137 | 139 | .MergeTable() |
| 138 | 140 | .OrderBy(sidx + " " + input.sort) |
| ... | ... | @@ -256,48 +258,109 @@ namespace NCC.Extend.LqTkjlb |
| 256 | 258 | } |
| 257 | 259 | #endregion |
| 258 | 260 | |
| 259 | - #region 导出拓客管理 | |
| 261 | + #region 获取拓客管理带中文名称的数据(简化版) | |
| 260 | 262 | /// <summary> |
| 261 | - /// 导出拓客管理 | |
| 263 | + /// 获取拓客管理带中文名称的数据(简化版,用于导出) | |
| 262 | 264 | /// </summary> |
| 263 | - /// <param name="input">请求参数</param> | |
| 265 | + /// <param name="eventId">活动编号(可选)</param> | |
| 266 | + /// <param name="endTime">截止时间(可选)</param> | |
| 264 | 267 | /// <returns></returns> |
| 268 | + [NonAction] | |
| 269 | + public async Task<List<TkjlbExportModel>> GetTkjlbWithChineseNamesSimple(string eventId = null, DateTime? endTime = null) | |
| 270 | + { | |
| 271 | + var data = await _db.Queryable<LqTkjlbEntity, LqMdxxEntity, LqEventEntity, UserEntity>( | |
| 272 | + (tk, md, ev, user) => tk.StoreId == md.Id && tk.EventId == ev.Id && tk.ExpansionUserId == user.Id | |
| 273 | + ) | |
| 274 | + .WhereIF(!string.IsNullOrEmpty(eventId), (tk, md, ev, user) => tk.EventId == eventId) | |
| 275 | + .WhereIF(endTime.HasValue, (tk, md, ev, user) => tk.ExpansionTime <= endTime.Value) | |
| 276 | + .Select((tk, md, ev, user) => new TkjlbExportModel | |
| 277 | + { | |
| 278 | + id = tk.Id, | |
| 279 | + expansionTime = tk.ExpansionTime, | |
| 280 | + expansionUserId = tk.ExpansionUserId, | |
| 281 | + expansionUserName = user.RealName, | |
| 282 | + customerName = tk.CustomerName, | |
| 283 | + customerPhone = tk.CustomerPhone, | |
| 284 | + buyNumber = tk.BuyNumber, | |
| 285 | + paymentMethod = tk.PaymentMethod, | |
| 286 | + isAddWeChat = tk.IsAddWeChat, | |
| 287 | + remarks = tk.Remarks, | |
| 288 | + storeId = tk.StoreId, | |
| 289 | + storeName = md.Dm, | |
| 290 | + teamName = tk.TeamName, | |
| 291 | + eventId = tk.EventId, | |
| 292 | + eventName = ev.EventName, | |
| 293 | + }) | |
| 294 | + .MergeTable() | |
| 295 | + .OrderBy("expansionTime desc") | |
| 296 | + .ToListAsync(); | |
| 297 | + | |
| 298 | + return data; | |
| 299 | + } | |
| 300 | + #endregion | |
| 301 | + | |
| 302 | + #region 导出拓客管理 | |
| 303 | + /// <summary> | |
| 304 | + /// 导出拓客管理(固定字段,显示中文名称) | |
| 305 | + /// </summary> | |
| 306 | + /// <param name="eventId">活动编号(可选)</param> | |
| 307 | + /// <param name="endTime">截止时间(可选)</param> | |
| 308 | + /// <returns>导出文件信息</returns> | |
| 265 | 309 | [HttpGet("Actions/Export")] |
| 266 | - public async Task<dynamic> Export([FromQuery] LqTkjlbListQueryInput input) | |
| 310 | + public async Task<dynamic> Export([FromQuery] string eventId = null, [FromQuery] DateTime? endTime = null) | |
| 267 | 311 | { |
| 268 | - var userInfo = await _userManager.GetUserInfo(); | |
| 269 | - var exportData = new List<LqTkjlbListOutput>(); | |
| 270 | - if (input.dataType == 0) | |
| 312 | + try | |
| 271 | 313 | { |
| 272 | - var data = Clay.Object(await this.GetList(input)); | |
| 273 | - exportData = data.Solidify<PageResult<LqTkjlbListOutput>>().list; | |
| 274 | - } | |
| 275 | - else | |
| 276 | - { | |
| 277 | - exportData = await this.GetNoPagingList(input); | |
| 278 | - } | |
| 279 | - List<ParamsModel> paramList = | |
| 280 | - "[{\"value\":\"拓客编号\",\"field\":\"id\"},{\"value\":\"拓客人员\",\"field\":\"tkry\"},{\"value\":\"拓客时间\",\"field\":\"tksj\"},{\"value\":\"顾客姓名\",\"field\":\"gkxm\"},{\"value\":\"电话号码\",\"field\":\"dhhm\"},{\"value\":\"购买张数\",\"field\":\"gmzs\"},{\"value\":\"支付方式\",\"field\":\"zffs\"},{\"value\":\"是否加微信\",\"field\":\"sfjwx\"},{\"value\":\"备注\",\"field\":\"bz\"},{\"value\":\"所属门店\",\"field\":\"ssmd\"},{\"value\":\"所属战队\",\"field\":\"sszd\"},]".ToList<ParamsModel>(); | |
| 281 | - ExcelConfig excelconfig = new ExcelConfig(); | |
| 282 | - excelconfig.FileName = "拓客管理.xls"; | |
| 283 | - excelconfig.HeadFont = "微软雅黑"; | |
| 284 | - excelconfig.HeadPoint = 10; | |
| 285 | - excelconfig.IsAllSizeColumn = true; | |
| 286 | - excelconfig.ColumnModel = new List<ExcelColumnModel>(); | |
| 287 | - List<string> selectKeyList = input.selectKey.Split(',').ToList(); | |
| 288 | - foreach (var item in selectKeyList) | |
| 289 | - { | |
| 290 | - var isExist = paramList.Find(p => p.field == item); | |
| 291 | - if (isExist != null) | |
| 314 | + var userInfo = await _userManager.GetUserInfo(); | |
| 315 | + | |
| 316 | + // 使用联合查询获取带中文名称的数据 | |
| 317 | + var exportData = await GetTkjlbWithChineseNamesSimple(eventId, endTime); | |
| 318 | + | |
| 319 | + // 检查数据是否为空 | |
| 320 | + if (exportData == null || exportData.Count == 0) | |
| 321 | + { | |
| 322 | + return new { name = "拓客管理.xls", url = "", message = "没有找到符合条件的数据" }; | |
| 323 | + } | |
| 324 | + | |
| 325 | + // 固定导出字段 | |
| 326 | + List<ParamsModel> paramList = | |
| 327 | + "[{\"value\":\"拓客编号\",\"field\":\"id\"},{\"value\":\"拓客时间\",\"field\":\"expansionTime\"},{\"value\":\"拓客人员ID\",\"field\":\"expansionUserId\"},{\"value\":\"拓客人员姓名\",\"field\":\"expansionUserName\"},{\"value\":\"顾客姓名\",\"field\":\"customerName\"},{\"value\":\"顾客电话\",\"field\":\"customerPhone\"},{\"value\":\"购买张数\",\"field\":\"buyNumber\"},{\"value\":\"支付方式\",\"field\":\"paymentMethod\"},{\"value\":\"是否加微信\",\"field\":\"isAddWeChat\"},{\"value\":\"备注\",\"field\":\"remarks\"},{\"value\":\"门店ID\",\"field\":\"storeId\"},{\"value\":\"门店名称\",\"field\":\"storeName\"},{\"value\":\"战队名称\",\"field\":\"teamName\"},{\"value\":\"活动ID\",\"field\":\"eventId\"},{\"value\":\"活动名称\",\"field\":\"eventName\"}]".ToList<ParamsModel>(); | |
| 328 | + | |
| 329 | + // 检查paramList是否为空 | |
| 330 | + if (paramList == null || paramList.Count == 0) | |
| 292 | 331 | { |
| 293 | - excelconfig.ColumnModel.Add(new ExcelColumnModel() { Column = isExist.field, ExcelColumn = isExist.value }); | |
| 332 | + return new { name = "拓客管理.xls", url = "", message = "参数列表解析失败" }; | |
| 294 | 333 | } |
| 334 | + | |
| 335 | + ExcelConfig excelconfig = new ExcelConfig(); | |
| 336 | + excelconfig.FileName = "拓客管理" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xls"; | |
| 337 | + excelconfig.HeadFont = "微软雅黑"; | |
| 338 | + excelconfig.HeadPoint = 10; | |
| 339 | + excelconfig.IsAllSizeColumn = true; | |
| 340 | + excelconfig.ColumnModel = new List<ExcelColumnModel>(); | |
| 341 | + | |
| 342 | + // 固定字段列表 | |
| 343 | + List<string> selectKeyList = new List<string> { "id", "expansionTime", "expansionUserId", "expansionUserName", "customerName", "customerPhone", "buyNumber", "paymentMethod", "isAddWeChat", "remarks", "storeId", "storeName", "teamName", "eventId", "eventName" }; | |
| 344 | + | |
| 345 | + foreach (var item in selectKeyList) | |
| 346 | + { | |
| 347 | + var isExist = paramList.Find(p => p.field == item); | |
| 348 | + if (isExist != null) | |
| 349 | + { | |
| 350 | + excelconfig.ColumnModel.Add(new ExcelColumnModel() { Column = isExist.field, ExcelColumn = isExist.value }); | |
| 351 | + } | |
| 352 | + } | |
| 353 | + | |
| 354 | + var addPath = FileVariable.TemporaryFilePath + excelconfig.FileName; | |
| 355 | + ExcelExportHelper<TkjlbExportModel>.Export(exportData, excelconfig, addPath); | |
| 356 | + var fileName = _userManager.UserId + "|" + excelconfig.FileName + "|temporary"; | |
| 357 | + var output = new { name = excelconfig.FileName, url = "/api/File/Download?encryption=" + DESCEncryption.Encrypt(fileName, "NCC") }; | |
| 358 | + return output; | |
| 359 | + } | |
| 360 | + catch (Exception ex) | |
| 361 | + { | |
| 362 | + return new { name = "拓客管理" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xls", url = "", message = $"导出失败: {ex.Message}", stackTrace = ex.StackTrace }; | |
| 295 | 363 | } |
| 296 | - var addPath = FileVariable.TemporaryFilePath + excelconfig.FileName; | |
| 297 | - ExcelExportHelper<LqTkjlbListOutput>.Export(exportData, excelconfig, addPath); | |
| 298 | - var fileName = _userManager.UserId + "|" + addPath + "|xls"; | |
| 299 | - var output = new { name = excelconfig.FileName, url = "/api/File/Download?encryption=" + DESCEncryption.Encrypt(fileName, "NCC") }; | |
| 300 | - return output; | |
| 301 | 364 | } |
| 302 | 365 | #endregion |
| 303 | 366 | ... | ... |