Commit 9864a8182636946663cc930a1e7b24f218e8c8d2

Authored by “wangming”
1 parent 28404662

feat: 优化拓客管理功能

- 新增 TkjlbExportModel DTO 类,将导出模型从服务层分离到 DTO 层
- 修复拓客管理导出功能的下载地址500错误
- 优化拓客管理列表页面:
  * 将活动编号搜索改为下拉框选择
  * 调整列宽度,拓客编号列加宽,备注列移除宽度限制
  * 移除编辑、删除、批量删除按钮
  * 优化表格样式和用户体验
- 简化导出功能,固定导出字段,支持活动编号和截止时间筛选
- 修复开单记录表导出功能,添加中文名称显示
- 创建临时文件目录以支持文件导出功能
antis-ncc-admin/src/views/lqTkjlb/ExportBox.vue
1 <template> 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 </el-form-item> 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 </el-form-item> 34 </el-form-item>
20 </el-form> 35 </el-form>
21 <span slot="footer" class="dialog-footer"> 36 <span slot="footer" class="dialog-footer">
22 <el-button @click="visible=false">取 消</el-button> 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 </span> 39 </span>
25 </el-dialog> 40 </el-dialog>
26 </template> 41 </template>
27 42
28 <script> 43 <script>
  44 +import { getLqEventList } from '@/api/extend/lqevent'
  45 +
29 export default { 46 export default {
30 data() { 47 data() {
31 return { 48 return {
32 visible: false, 49 visible: false,
33 btnLoading: false, 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 methods: { 59 methods: {
42 - init(columnList) { 60 + init() {
43 this.visible = true 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 downLoad() { 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,4 +114,32 @@ export default {
63 >>> .el-dialog__body { 114 >>> .el-dialog__body {
64 padding: 20px !important; 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 </style> 145 </style>
67 \ No newline at end of file 146 \ No newline at end of file
antis-ncc-admin/src/views/lqTkjlb/index.vue
@@ -12,7 +12,14 @@ @@ -12,7 +12,14 @@
12 </el-col> 12 </el-col>
13 <el-col :span="6"> 13 <el-col :span="6">
14 <el-form-item label="拓客活动"> 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 </el-form-item> 23 </el-form-item>
17 </el-col> 24 </el-col>
18 <el-col :span="6"> 25 <el-col :span="6">
@@ -20,6 +27,11 @@ @@ -20,6 +27,11 @@
20 <userSelect v-model="query.expansionUserId" placeholder="请选择拓客人员" /> 27 <userSelect v-model="query.expansionUserId" placeholder="请选择拓客人员" />
21 </el-form-item> 28 </el-form-item>
22 </el-col> 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 <template v-if="showAll"> 36 <template v-if="showAll">
25 <el-col :span="6"> 37 <el-col :span="6">
@@ -53,6 +65,11 @@ @@ -53,6 +65,11 @@
53 </el-select> 65 </el-select>
54 </el-form-item> 66 </el-form-item>
55 </el-col> 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 </template> 73 </template>
57 <el-col :span="6"> 74 <el-col :span="6">
58 <el-form-item> 75 <el-form-item>
@@ -67,9 +84,7 @@ @@ -67,9 +84,7 @@
67 <div class="NCC-common-layout-main NCC-flex-main"> 84 <div class="NCC-common-layout-main NCC-flex-main">
68 <div class="NCC-common-head"> 85 <div class="NCC-common-head">
69 <div> 86 <div>
70 - <el-button type="primary" icon="el-icon-plus" @click="addOrUpdateHandle()">新增</el-button>  
71 <el-button type="text" icon="el-icon-download" @click="exportData()">导出</el-button> 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 <el-button type="success" icon="el-icon-s-data" @click="goToReport()">拓客报表</el-button> 88 <el-button type="success" icon="el-icon-s-data" @click="goToReport()">拓客报表</el-button>
74 </div> 89 </div>
75 <div class="NCC-common-head-right"> 90 <div class="NCC-common-head-right">
@@ -79,32 +94,28 @@ @@ -79,32 +94,28 @@
79 <screenfull isContainer /> 94 <screenfull isContainer />
80 </div> 95 </div>
81 </div> 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 <template slot-scope="scope">{{ scope.row.paymentMethod | dynamicText(zffsOptions) }}</template> 107 <template slot-scope="scope">{{ scope.row.paymentMethod | dynamicText(zffsOptions) }}</template>
91 </el-table-column> 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 <template slot-scope="scope">{{ scope.row.isAddWeChat | dynamicText(sfjwxOptions) }}</template> 110 <template slot-scope="scope">{{ scope.row.isAddWeChat | dynamicText(sfjwxOptions) }}</template>
94 </el-table-column> 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 </NCC-table> 114 </NCC-table>
103 <pagination :total="total" :page.sync="listQuery.currentPage" :limit.sync="listQuery.pageSize" 115 <pagination :total="total" :page.sync="listQuery.currentPage" :limit.sync="listQuery.pageSize"
104 @pagination="initData" /> 116 @pagination="initData" />
105 </div> 117 </div>
106 </div> 118 </div>
107 - <NCC-Form v-if="formVisible" ref="NCCForm" @refresh="refresh" />  
108 <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" /> 119 <ExportBox v-if="exportBoxVisible" ref="ExportBox" @download="download" />
109 </div> 120 </div>
110 </template> 121 </template>
@@ -113,19 +124,20 @@ @@ -113,19 +124,20 @@
113 import { 124 import {
114 getDictionaryDataSelector 125 getDictionaryDataSelector
115 } from '@/api/systemData/dictionary' 126 } from '@/api/systemData/dictionary'
116 - import NCCForm from './Form'  
117 import ExportBox from './ExportBox' 127 import ExportBox from './ExportBox'
118 import { 128 import {
119 previewDataInterface 129 previewDataInterface
120 } from '@/api/systemData/dataInterface' 130 } from '@/api/systemData/dataInterface'
  131 + import { getLqEventList } from '@/api/extend/lqevent'
121 export default { 132 export default {
122 components: { 133 components: {
123 - NCCForm,  
124 ExportBox 134 ExportBox
125 }, 135 },
126 data() { 136 data() {
127 return { 137 return {
128 showAll: false, 138 showAll: false,
  139 + eventList: [],
  140 + eventListLoading: false,
129 query: { 141 query: {
130 id: undefined, 142 id: undefined,
131 expansionUserId: undefined, 143 expansionUserId: undefined,
@@ -137,12 +149,11 @@ @@ -137,12 +149,11 @@
137 isAddWeChat: undefined, 149 isAddWeChat: undefined,
138 remarks: undefined, 150 remarks: undefined,
139 eventId: undefined, 151 eventId: undefined,
140 - ssmd: undefined,  
141 - sszd: undefined, 152 + storeId: undefined,
  153 + teamName: undefined,
142 }, 154 },
143 list: [], 155 list: [],
144 listLoading: true, 156 listLoading: true,
145 - multipleSelection: [],  
146 total: 0, 157 total: 0,
147 listQuery: { 158 listQuery: {
148 currentPage: 1, 159 currentPage: 1,
@@ -150,17 +161,24 @@ @@ -150,17 +161,24 @@
150 sort: "desc", 161 sort: "desc",
151 sidx: "", 162 sidx: "",
152 }, 163 },
153 - formVisible: false,  
154 exportBoxVisible: false, 164 exportBoxVisible: false,
155 columnList: [{ 165 columnList: [{
156 prop: 'id', 166 prop: 'id',
157 label: '拓客编号' 167 label: '拓客编号'
158 }, 168 },
159 { 169 {
160 - prop: 'expansionUserId', 170 + prop: 'eventName',
  171 + label: '拓客活动'
  172 + },
  173 + {
  174 + prop: 'expansionUserName',
161 label: '拓客人员' 175 label: '拓客人员'
162 }, 176 },
163 { 177 {
  178 + prop: 'storeName',
  179 + label: '所属门店'
  180 + },
  181 + {
164 prop: 'expansionTime', 182 prop: 'expansionTime',
165 label: '拓客时间' 183 label: '拓客时间'
166 }, 184 },
@@ -185,20 +203,12 @@ @@ -185,20 +203,12 @@
185 label: '是否加微信' 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 zffsOptions: [{ 214 zffsOptions: [{
@@ -225,9 +235,34 @@ @@ -225,9 +235,34 @@
225 }, 235 },
226 computed: {}, 236 computed: {},
227 created() { 237 created() {
  238 + this.getEventList()
228 this.initData() 239 this.initData()
229 }, 240 },
230 methods: { 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 initData() { 266 initData() {
232 this.listLoading = true; 267 this.listLoading = true;
233 let _query = { 268 let _query = {
@@ -252,81 +287,43 @@ @@ -252,81 +287,43 @@
252 this.listLoading = false 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 exportData() { 290 exportData() {
312 this.exportBoxVisible = true 291 this.exportBoxVisible = true
313 this.$nextTick(() => { 292 this.$nextTick(() => {
314 - this.$refs.ExportBox.init(this.columnList) 293 + this.$refs.ExportBox.init()
315 }) 294 })
316 }, 295 },
317 download(data) { 296 download(data) {
  297 + // 使用简化的参数
318 let query = { 298 let query = {
319 - ...data,  
320 - ...this.listQuery,  
321 - ...this.query 299 + eventId: data.eventId,
  300 + endTime: data.endTime
322 } 301 }
  302 +
323 request({ 303 request({
324 url: `/api/Extend/LqTkjlb/Actions/Export`, 304 url: `/api/Extend/LqTkjlb/Actions/Export`,
325 method: 'GET', 305 method: 'GET',
326 data: query 306 data: query
327 }).then(res => { 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 this.$refs.ExportBox.visible = false 327 this.$refs.ExportBox.visible = false
331 this.exportBoxVisible = false 328 this.exportBoxVisible = false
332 }) 329 })
@@ -340,10 +337,6 @@ @@ -340,10 +337,6 @@
340 } 337 }
341 this.initData() 338 this.initData()
342 }, 339 },
343 - refresh(isrRefresh) {  
344 - this.formVisible = false  
345 - if (isrRefresh) this.reset()  
346 - },  
347 reset() { 340 reset() {
348 for (let key in this.query) { 341 for (let key in this.query) {
349 this.query[key] = undefined 342 this.query[key] = undefined
@@ -364,3 +357,79 @@ @@ -364,3 +357,79 @@
364 } 357 }
365 } 358 }
366 </script> 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,7 +184,7 @@
184 "NCC_App": { 184 "NCC_App": {
185 "CodeAreasName": "SubDev,Food,Extend,test", 185 "CodeAreasName": "SubDev,Food,Extend,test",
186 //系统文件路径(末尾必须带斜杆) 186 //系统文件路径(末尾必须带斜杆)
187 - "SystemPath": "C:\\web\\NCC\\uu-resources\\", 187 + "SystemPath": "Files/",
188 //微信公众号允许上传文件类型 188 //微信公众号允许上传文件类型
189 "MPUploadFileType": "bmp,png,jpeg,jpg,gif,mp3,wma,wav,amr,mp4", 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,6 +23,16 @@ namespace NCC.Extend.Entitys.Dto.LqTkjlb
23 public string expansionUserId { get; set; } 23 public string expansionUserId { get; set; }
24 24
25 /// <summary> 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 /// </summary> 37 /// </summary>
28 public string expansionUserName { get; set; } 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,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 //通过会员id查询会员信息 355 //通过会员id查询会员信息
361 var memberInfo = await _db.Queryable<LqKhxxEntity>().Where(u => u.Id == entity.Kdhy).FirstAsync(); 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,6 +133,8 @@ namespace NCC.Extend.LqTkjlb
133 teamName = it.TeamName, 133 teamName = it.TeamName,
134 eventId = it.EventId, 134 eventId = it.EventId,
135 eventName = SqlFunc.Subqueryable<LqEventEntity>().Where(u => u.Id == it.EventId).Select(u => u.EventName), 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 .MergeTable() 139 .MergeTable()
138 .OrderBy(sidx + " " + input.sort) 140 .OrderBy(sidx + " " + input.sort)
@@ -256,48 +258,109 @@ namespace NCC.Extend.LqTkjlb @@ -256,48 +258,109 @@ namespace NCC.Extend.LqTkjlb
256 } 258 }
257 #endregion 259 #endregion
258 260
259 - #region 导出拓客管理 261 + #region 获取拓客管理带中文名称的数据(简化版)
260 /// <summary> 262 /// <summary>
261 - /// 导出拓客管理 263 + /// 获取拓客管理带中文名称的数据(简化版,用于导出)
262 /// </summary> 264 /// </summary>
263 - /// <param name="input">请求参数</param> 265 + /// <param name="eventId">活动编号(可选)</param>
  266 + /// <param name="endTime">截止时间(可选)</param>
264 /// <returns></returns> 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 [HttpGet("Actions/Export")] 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 #endregion 365 #endregion
303 366