Commit 3f8b942fd5773384cf463fe3ae90ee30b4767545

Authored by “wangming”
1 parent 910e21a0

feat: 添加业绩类型字段并修复转卡业绩计算逻辑

- 在开单品项表、健康师业绩表、科技老师业绩表、消耗品项表、业绩表等10个表中添加F_PerformanceType字段
- 修复转卡时健康师和科技部老师业绩计算逻辑,按原业绩比例计算而非直接复制
- 修复退卡明细表F_SourceType字段赋值错误(使用品项分类而非开单类型)
- 添加SQL脚本用于添加业绩类型字段和更新历史数据
- 业绩类型根据品项表(lq_xmzl)的fl3字段设置
antis-ncc-admin/src/views/lqHytkHytk/Form.vue
1 1 <template>
2   - <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3   - <el-row :gutter="15" class="" >
4   - <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
5   - <el-col :span="8" v-if="false" >
6   - <el-form-item label="退卡编号" prop="id">
7   - <el-input v-model="dataForm.id" placeholder="请输入" clearable :style='{"width":"100%"}' >
8   - </el-input>
9   - </el-form-item>
10   - </el-col>
11   - <el-col :span="8">
12   - <el-form-item label="门店" prop="md" required>
13   - <el-select v-model="dataForm.md" placeholder="请选择" clearable :style='{"width":"100%"}' filterable @change="handleMdChange">
14   - <el-option v-for="(item, index) in mdOptions" :key="index" :label="item.fullName" :value="item.id" ></el-option>
15   - </el-select>
16   - </el-form-item>
17   - </el-col>
18   - <el-col :span="8">
  2 + <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情' : '编辑'" :close-on-click-modal="false"
  3 + :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
  4 + <el-row :gutter="15" class="">
  5 + <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right"
  6 + :disabled="!!isDetail" :rules="rules">
  7 + <el-col :span="8" v-if="false">
  8 + <el-form-item label="退卡编号" prop="id">
  9 + <el-input v-model="dataForm.id" placeholder="请输入" clearable :style='{ "width": "100%" }'>
  10 + </el-input>
  11 + </el-form-item>
  12 + </el-col>
  13 + <el-col :span="8">
  14 + <el-form-item label="门店" prop="md" required>
  15 + <el-select v-model="dataForm.md" placeholder="请选择" clearable :style='{ "width": "100%" }'
  16 + filterable @change="handleMdChange">
  17 + <el-option v-for="(item, index) in mdOptions" :key="index" :label="item.fullName"
  18 + :value="item.id"></el-option>
  19 + </el-select>
  20 + </el-form-item>
  21 + </el-col>
  22 + <el-col :span="8">
19 23 <el-form-item label="退卡时间" prop="tksj">
20   - <el-date-picker v-model="dataForm.tksj" placeholder="请选择" clearable :style='{"width":"100%"}' type='date' format="yyyy-MM-dd" value-format="timestamp" >
  24 + <el-date-picker v-model="dataForm.tksj" placeholder="请选择" clearable :style='{ "width": "100%" }'
  25 + type='date' format="yyyy-MM-dd" value-format="timestamp">
21 26 </el-date-picker>
22 27 </el-form-item>
23 28 </el-col>
24   - <el-col :span="8" v-if="false">
25   - <el-form-item label="门店编号" prop="mdbh">
26   - <el-input v-model="dataForm.mdbh" placeholder="自动填充" clearable readonly :style='{"width":"100%"}' >
27   - </el-input>
28   - </el-form-item>
29   - </el-col>
30   - <el-col :span="8" v-if="false">
31   - <el-form-item label="门店名称" prop="mdmc">
32   - <el-input v-model="dataForm.mdmc" placeholder="自动填充" clearable readonly :style='{"width":"100%"}' >
33   - </el-input>
34   - </el-form-item>
35   - </el-col>
36   - <el-col :span="8">
37   - <el-form-item label="会员" prop="hy" required>
38   - <el-select v-model="dataForm.hy" placeholder="请选择" clearable :style='{"width":"100%"}' filterable @change="handleHyChange">
39   - <el-option v-for="(item, index) in hyOptions" :key="index" :label="item.fullName" :value="item.id" ></el-option>
40   - </el-select>
41   - </el-form-item>
42   - </el-col>
43   - <el-col :span="8" v-if="false">
44   - <el-form-item label="会员姓名" prop="hymc">
45   - <el-input v-model="dataForm.hymc" placeholder="自动填充" clearable readonly :style='{"width":"100%"}' >
46   - </el-input>
47   - </el-form-item>
48   - </el-col>
49   - <el-col :span="8" v-if="false">
50   - <el-form-item label="会员账号" prop="hyzh">
51   - <el-input v-model="dataForm.hyzh" placeholder="自动填充" clearable readonly :style='{"width":"100%"}' >
52   - </el-input>
53   - </el-form-item>
54   - </el-col>
55   - <el-col :span="8">
56   - <el-form-item label="退款金额" prop="tkje">
57   - <el-input v-model="dataForm.tkje" placeholder="自动计算" clearable readonly :style='{"width":"100%"}'>
58   - <template slot="append">元</template>
59   - </el-input>
60   - </el-form-item>
61   - </el-col>
62   - <el-col :span="8">
63   - <el-form-item label="手工费用" prop="sgfy">
64   - <el-input v-model="dataForm.sgfy" placeholder="自动计算" clearable readonly :style='{"width":"100%"}'>
65   - <template slot="append">元</template>
66   - </el-input>
67   - </el-form-item>
68   - </el-col>
69   - <el-col :span="16"></el-col>
70   - <el-col :span="24" v-if="false" >
71   - <el-form-item label="退卡品项" prop="tkpx">
72   - <el-input v-model="dataForm.tkpx" placeholder="请输入" clearable :style='{"width":"100%"}' >
73   - </el-input>
74   - </el-form-item>
75   - </el-col>
76   - <el-col :span="24" v-if="dataForm.hy && pxOptions.length > 0">
77   - <el-form-item label="会员剩余品项" label-width="100px">
78   - <div class="member-remaining-items">
79   - <div class="remaining-items-header">
80   - <span class="items-title">会员剩余品项列表 ({{ pxOptions.length }} 个)</span>
81   - </div>
82   - <div class="remaining-items-list">
83   - <div v-for="(item, index) in pxOptions" :key="index" class="remaining-item-row" :class="{ 'disabled': item.RemainingCount <= 0 }">
84   - <div class="item-name">{{ item.fullName }}</div>
85   - <div class="item-price">¥{{ item.ItemPrice || 0 }}</div>
86   - <div class="item-quantity" :class="{ 'zero': item.RemainingCount <= 0 }">
87   - 剩余: {{ item.RemainingCount || 0 }}
88   - </div>
89   - <div class="item-source">{{ item.sourceType || '购买' }}</div>
  29 + <el-col :span="8" v-if="false">
  30 + <el-form-item label="门店编号" prop="mdbh">
  31 + <el-input v-model="dataForm.mdbh" placeholder="自动填充" clearable readonly
  32 + :style='{ "width": "100%" }'>
  33 + </el-input>
  34 + </el-form-item>
  35 + </el-col>
  36 + <el-col :span="8" v-if="false">
  37 + <el-form-item label="门店名称" prop="mdmc">
  38 + <el-input v-model="dataForm.mdmc" placeholder="自动填充" clearable readonly
  39 + :style='{ "width": "100%" }'>
  40 + </el-input>
  41 + </el-form-item>
  42 + </el-col>
  43 + <el-col :span="8">
  44 + <el-form-item label="会员" prop="hy" required>
  45 + <el-select v-model="dataForm.hy" placeholder="请选择" clearable :style='{ "width": "100%" }'
  46 + filterable @change="handleHyChange">
  47 + <el-option v-for="(item, index) in hyOptions" :key="index" :label="item.fullName"
  48 + :value="item.id"></el-option>
  49 + </el-select>
  50 + </el-form-item>
  51 + </el-col>
  52 + <el-col :span="8" v-if="false">
  53 + <el-form-item label="会员姓名" prop="hymc">
  54 + <el-input v-model="dataForm.hymc" placeholder="自动填充" clearable readonly
  55 + :style='{ "width": "100%" }'>
  56 + </el-input>
  57 + </el-form-item>
  58 + </el-col>
  59 + <el-col :span="8" v-if="false">
  60 + <el-form-item label="会员账号" prop="hyzh">
  61 + <el-input v-model="dataForm.hyzh" placeholder="自动填充" clearable readonly
  62 + :style='{ "width": "100%" }'>
  63 + </el-input>
  64 + </el-form-item>
  65 + </el-col>
  66 + <el-col :span="8">
  67 + <el-form-item label="退款金额" prop="tkje">
  68 + <el-input v-model="dataForm.tkje" placeholder="自动计算" clearable readonly
  69 + :style='{ "width": "100%" }'>
  70 + <template slot="append">元</template>
  71 + </el-input>
  72 + </el-form-item>
  73 + </el-col>
  74 + <el-col :span="8">
  75 + <el-form-item label="手工费用" prop="sgfy">
  76 + <el-input v-model="dataForm.sgfy" placeholder="自动计算" clearable readonly
  77 + :style='{ "width": "100%" }'>
  78 + <template slot="append">元</template>
  79 + </el-input>
  80 + </el-form-item>
  81 + </el-col>
  82 + <el-col :span="16"></el-col>
  83 + <el-col :span="24" v-if="false">
  84 + <el-form-item label="退卡品项" prop="tkpx">
  85 + <el-input v-model="dataForm.tkpx" placeholder="请输入" clearable :style='{ "width": "100%" }'>
  86 + </el-input>
  87 + </el-form-item>
  88 + </el-col>
  89 + <el-col :span="24" v-if="dataForm.hy && pxOptions.length > 0">
  90 + <el-form-item label="会员剩余品项" label-width="100px">
  91 + <div class="member-remaining-items">
  92 + <div class="remaining-items-header">
  93 + <span class="items-title">会员剩余品项列表 ({{ pxOptions.length }} 个)</span>
  94 + </div>
  95 + <div class="remaining-items-list">
  96 + <div v-for="(item, index) in pxOptions" :key="index" class="remaining-item-row"
  97 + :class="{ 'disabled': item.RemainingCount <= 0 }">
  98 + <div class="item-name">{{ item.fullName }}</div>
  99 + <div class="item-price">¥{{ item.ItemPrice || 0 }}</div>
  100 + <div class="item-quantity" :class="{ 'zero': item.RemainingCount <= 0 }">
  101 + 剩余: {{ item.RemainingCount || 0 }}
90 102 </div>
  103 + <div class="item-source">{{ item.sourceType || '购买' }}</div>
91 104 </div>
92 105 </div>
93   - </el-form-item>
94   - </el-col>
95   - <el-col :span="24">
  106 + </div>
  107 + </el-form-item>
  108 + </el-col>
  109 + <el-col :span="24">
96 110 <el-form-item label-width="0">
97 111 <div class="table-header">
98 112 <span class="table-title">品项明细</span>
99   - <el-button v-if="!dataForm.id" type="warning" size="mini" icon="el-icon-plus" @click="addHandleLqXhPxmxEntityList()">新增品项</el-button>
  113 + <el-button v-if="!dataForm.id" type="warning" size="mini" icon="el-icon-plus"
  114 + @click="addHandleLqXhPxmxEntityList()">新增品项</el-button>
100 115 </div>
101   -
  116 +
102 117 <!-- 品项列表 -->
103 118 <div class="px-list-container">
104 119 <div v-for="(px, pxIndex) in dataForm.lqHytkMxList" :key="pxIndex" class="px-item">
... ... @@ -106,16 +121,20 @@
106 121 <div class="px-basic-info">
107 122 <div class="px-item-header">
108 123 <span class="px-item-title">品项明细</span>
109   - <el-button v-if="!dataForm.id"size="mini" type="danger" icon="el-icon-delete" @click="handleDelLqXhPxmxEntityList(pxIndex)">删除</el-button>
  124 + <el-button v-if="!dataForm.id" size="mini" type="danger" icon="el-icon-delete"
  125 + @click="handleDelLqXhPxmxEntityList(pxIndex)">删除</el-button>
110 126 </div>
111   -
  127 +
112 128 <!-- 品项选择 -->
113 129 <div class="px-select-row">
114   - <el-select v-model="px.pxid" placeholder="请选择品项" clearable filterable @change="handlePxChange(pxIndex, px)" style="width: 200px;">
115   - <el-option v-for="(item, index) in pxOptions" :key="index" :label="item.fullName+'(剩余: '+(item.RemainingCount || 0)+',类型:'+item.sourceType+')'" :value="item.pxid" :disabled="item.disabled"></el-option>
  130 + <el-select v-model="px.pxid" placeholder="请选择品项" clearable filterable
  131 + @change="handlePxChange(pxIndex, px)" style="width: 200px;">
  132 + <el-option v-for="(item, index) in pxOptions" :key="index"
  133 + :label="item.fullName + '(剩余: ' + (item.RemainingCount || 0) + ',类型:' + item.sourceType + ')'"
  134 + :value="item.pxid" :disabled="item.disabled"></el-option>
116 135 </el-select>
117 136 </div>
118   -
  137 +
119 138 <!-- 品项详细信息 -->
120 139 <div class="px-detail-info" v-if="px.px">
121 140 <div class="px-detail-row">
... ... @@ -149,13 +168,17 @@
149 168 </div>
150 169 <div class="px-detail-item">
151 170 <span class="px-detail-label">总业绩:</span>
152   - <span class="px-detail-value">{{ (px.projectNumber || 1) * (px.pxjg || 0) }}</span>
  171 + <span class="px-detail-value">{{ (px.projectNumber || 1) * (px.pxjg ||
  172 + 0) }}</span>
153 173 </div>
154 174 </div>
155   -
  175 +
156 176 <!-- 消费数量输入 -->
157 177 <div class="px-consumption-row">
158   - <el-input-number v-model="px.projectNumber" :min="1" :max="getRemainingCount(px)" placeholder="消费数量" size="mini" style="width: 120px;" @change="onPxProjectNumberChange(pxIndex, $event)"></el-input-number>
  178 + <el-input-number v-model="px.projectNumber" :min="1"
  179 + :max="getRemainingCount(px)" placeholder="消费数量" size="mini"
  180 + style="width: 120px;"
  181 + @change="onPxProjectNumberChange(pxIndex, $event)"></el-input-number>
159 182 </div>
160 183 </div>
161 184 </div>
... ... @@ -164,36 +187,48 @@
164 187 <div class="px-staff-section">
165 188 <div class="px-staff-header">
166 189 <span class="px-staff-title">健康师业绩</span>
167   - <el-button v-if="!dataForm.id" size="mini" type="success" icon="el-icon-plus" @click="addPxJks(pxIndex)">添加健康师</el-button>
  190 + <el-button v-if="!dataForm.id" size="mini" type="success" icon="el-icon-plus"
  191 + @click="addPxJks(pxIndex)">添加健康师</el-button>
168 192 </div>
169 193 <div class="px-staff-list">
170   - <div v-for="(jks, jksIndex) in px.lqHytkJksyjList" :key="jksIndex" class="px-staff-row">
  194 + <div v-for="(jks, jksIndex) in px.lqHytkJksyjList" :key="jksIndex"
  195 + class="px-staff-row">
171 196 <div class="px-staff-item">
172 197 <div class="px-staff-fields">
173 198 <div class="px-staff-field">
174 199 <label>健康师</label>
175   - <el-select v-model="jks.jks" placeholder="选择健康师" clearable filterable size="mini" style="width: 200px;" @change="handleJksChange(pxIndex, jksIndex, jks)">
176   - <el-option v-for="(item, index) in jksOptions" :key="index" :label="item.fullName" :value="item.id"></el-option>
  200 + <el-select v-model="jks.jks" placeholder="选择健康师" clearable
  201 + filterable size="mini" style="width: 200px;"
  202 + @change="handleJksChange(pxIndex, jksIndex, jks)">
  203 + <el-option v-for="(item, index) in jksOptions" :key="index"
  204 + :label="item.fullName" :value="item.id"></el-option>
177 205 </el-select>
178 206 </div>
179 207 <div class="px-staff-field">
180 208 <label>业绩</label>
181   - <el-input v-model="jks.jksyj" placeholder="请输入业绩" size="mini" style="width: 120px;" @input="formatPxStaffNumber(pxIndex, jksIndex, 'jksyj', 'lqHytkJksyjList')">
  209 + <el-input v-model="jks.jksyj" placeholder="请输入业绩" size="mini"
  210 + style="width: 120px;"
  211 + @input="formatPxStaffNumber(pxIndex, jksIndex, 'jksyj', 'lqHytkJksyjList')">
182 212 <template slot="append">元</template>
183 213 </el-input>
184 214 </div>
185 215 <div class="px-staff-field" v-show="false">
186 216 <label>手工费</label>
187   - <el-input v-model="jks.laborCost" placeholder="手工费" size="mini" style="width: 120px;" @input="formatPxStaffNumber(pxIndex, jksIndex, 'laborCost', 'lqHytkJksyjList')">
  217 + <el-input v-model="jks.laborCost" placeholder="手工费" size="mini"
  218 + style="width: 120px;"
  219 + @input="formatPxStaffNumber(pxIndex, jksIndex, 'laborCost', 'lqHytkJksyjList')">
188 220 <template slot="append">元</template>
189 221 </el-input>
190 222 </div>
191 223 <div class="px-staff-field">
192 224 <label>次数</label>
193   - <el-input-number v-model="jks.kdpxNumber" :min="1" :max="999" placeholder="次数" size="mini" style="width: 120px;" @change="onJksNumberChange(pxIndex, jksIndex, $event)"></el-input-number>
  225 + <el-input-number v-model="jks.kdpxNumber" :min="1" :max="999"
  226 + placeholder="次数" size="mini" style="width: 120px;"
  227 + @change="onJksNumberChange(pxIndex, jksIndex, $event)"></el-input-number>
194 228 </div>
195 229 <div class="px-staff-field" v-if="!dataForm.id">
196   - <el-button size="mini" type="danger" icon="el-icon-delete" @click="removePxJks(pxIndex, jksIndex)">删除</el-button>
  230 + <el-button size="mini" type="danger" icon="el-icon-delete"
  231 + @click="removePxJks(pxIndex, jksIndex)">删除</el-button>
197 232 </div>
198 233 </div>
199 234 </div>
... ... @@ -202,46 +237,60 @@
202 237 </div>
203 238  
204 239 <!-- 科技部老师业绩区域 - 仅当品项类型为科美时显示 -->
205   - <div class="px-staff-section" v-if="px.qt2 === '科美'" :key="'kjb-' + pxIndex + '-' + px.qt2">
  240 + <div class="px-staff-section" v-if="px.qt2 === '科美'"
  241 + :key="'kjb-' + pxIndex + '-' + px.qt2">
206 242 <div class="px-staff-header">
207 243 <span class="px-staff-title">科技部老师业绩</span>
208   - <el-button v-if="!dataForm.id" size="mini" type="success" icon="el-icon-plus" @click="addPxKjb(pxIndex)">添加科技部老师</el-button>
  244 + <el-button v-if="!dataForm.id" size="mini" type="success" icon="el-icon-plus"
  245 + @click="addPxKjb(pxIndex)">添加科技部老师</el-button>
209 246 </div>
210 247 <div class="px-staff-list">
211   - <div v-for="(kjb, kjbIndex) in px.lqHytkKjbsyjList" :key="kjbIndex" class="px-staff-row">
  248 + <div v-for="(kjb, kjbIndex) in px.lqHytkKjbsyjList" :key="kjbIndex"
  249 + class="px-staff-row">
212 250 <div class="px-staff-item">
213 251 <div class="px-staff-fields">
214 252 <div class="px-staff-field">
215 253 <label>科技部老师</label>
216   - <el-select v-model="kjb.kjbls" placeholder="选择科技部老师" clearable filterable size="mini" style="width: 200px;" @change="handleKjbChange(pxIndex, kjbIndex, kjb)">
217   - <el-option v-for="(item, index) in kjbOptions" :key="index" :label="item.fullName" :value="item.id"></el-option>
  254 + <el-select v-model="kjb.kjbls" placeholder="选择科技部老师" clearable
  255 + filterable size="mini" style="width: 200px;"
  256 + @change="handleKjbChange(pxIndex, kjbIndex, kjb)">
  257 + <el-option v-for="(item, index) in kjbOptions" :key="index"
  258 + :label="item.fullName" :value="item.id"></el-option>
218 259 </el-select>
219 260 </div>
220 261 <div class="px-staff-field">
221 262 <label>业绩</label>
222   - <el-input v-model="kjb.kjblsyj" placeholder="请输入业绩" size="mini" style="width: 120px;" @input="formatPxStaffNumber(pxIndex, kjbIndex, 'kjblsyj', 'lqHytkKjbsyjList')">
  263 + <el-input v-model="kjb.kjblsyj" placeholder="请输入业绩" size="mini"
  264 + style="width: 120px;"
  265 + @input="formatPxStaffNumber(pxIndex, kjbIndex, 'kjblsyj', 'lqHytkKjbsyjList')">
223 266 <template slot="append">元</template>
224 267 </el-input>
225 268 </div>
226   - <div class="px-staff-field" v-show="false" style="justify-content: space-around;padding-bottom: 30rpx;">
  269 + <div class="px-staff-field" v-show="false"
  270 + style="justify-content: space-around;padding-bottom: 30rpx;">
227 271 <label>手工费</label>
228   - <el-input v-model="kjb.laborCost" placeholder="手工费" size="mini" style="width: 120px;" @input="formatPxStaffNumber(pxIndex, kjbIndex, 'laborCost', 'lqHytkKjbsyjList')">
  272 + <el-input v-model="kjb.laborCost" placeholder="手工费" size="mini"
  273 + style="width: 120px;"
  274 + @input="formatPxStaffNumber(pxIndex, kjbIndex, 'laborCost', 'lqHytkKjbsyjList')">
229 275 <template slot="append">元</template>
230 276 </el-input>
231 277 </div>
232 278 <div class="px-staff-field">
233 279 <label>次数</label>
234   - <el-input-number v-model="kjb.hdpxNumber" :min="1" :max="999" placeholder="次数" size="mini" style="width: 120px;" @change="onKjbNumberChange(pxIndex, kjbIndex, $event)"></el-input-number>
  280 + <el-input-number v-model="kjb.hdpxNumber" :min="1" :max="999"
  281 + placeholder="次数" size="mini" style="width: 120px;"
  282 + @change="onKjbNumberChange(pxIndex, kjbIndex, $event)"></el-input-number>
235 283 </div>
236 284 <div class="px-staff-field" v-if="!dataForm.id">
237   - <el-button size="mini" type="danger" icon="el-icon-delete" @click="removePxKjb(pxIndex, kjbIndex)">删除</el-button>
  285 + <el-button size="mini" type="danger" icon="el-icon-delete"
  286 + @click="removePxKjb(pxIndex, kjbIndex)">删除</el-button>
238 287 </div>
239 288 </div>
240 289 </div>
241 290 </div>
242 291 </div>
243 292 </div>
244   -
  293 +
245 294 <!-- 非科美品项提示 -->
246 295 <div class="px-staff-section" v-if="px.qt2 && px.qt2 !== '科美'">
247 296 <div class="px-staff-header">
... ... @@ -257,18 +306,19 @@
257 306 </el-form-item>
258 307 </el-col>
259 308 <el-col :span="24">
260   - <el-form-item label="备注" prop="bz">
261   - <el-input v-model="dataForm.bz" placeholder="请输入" show-word-limit :style='{"width":"100%"}' type='textarea' :autosize='{"minRows":4,"maxRows":4}' >
262   - </el-input>
263   - </el-form-item>
264   - </el-col>
265   - <el-col :span="24">
266   - <el-form-item label="上传文件" prop="fileUrl">
267   - <NCC-UploadImg v-model="dataForm.fileUrl" :fileSize="30" sizeUnit="MB" :limit="9" >
268   - </NCC-UploadImg>
269   - </el-form-item>
270   - </el-col>
271   - </el-form>
  309 + <el-form-item label="备注" prop="bz">
  310 + <el-input v-model="dataForm.bz" placeholder="请输入" show-word-limit :style='{ "width": "100%" }'
  311 + type='textarea' :autosize='{ "minRows": 4, "maxRows": 4 }'>
  312 + </el-input>
  313 + </el-form-item>
  314 + </el-col>
  315 + <el-col :span="24">
  316 + <el-form-item label="上传文件" prop="fileUrl">
  317 + <NCC-UploadImg v-model="dataForm.fileUrl" :fileSize="30" sizeUnit="MB" :limit="9">
  318 + </NCC-UploadImg>
  319 + </el-form-item>
  320 + </el-col>
  321 + </el-form>
272 322 </el-row>
273 323 <span slot="footer" class="dialog-footer">
274 324 <el-button @click="visible = false">取 消</el-button>
... ... @@ -277,291 +327,291 @@
277 327 </el-dialog>
278 328 </template>
279 329 <script>
280   - import request from '@/utils/request'
281   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
282   - import { previewDataInterface } from '@/api/systemData/dataInterface'
283   - import { getInfo } from '@/api/user'
284   - export default {
285   - components: {},
286   - props: [],
287   - data() {
288   - return {
289   - loading: false,
290   - visible: false,
291   - isDetail: false,
292   - dataForm: {
293   - id:'',
294   - id:undefined,
295   - md:undefined,
296   - mdbh:undefined,
297   - mdmc:undefined,
298   - hy:undefined,
299   - hymc:undefined,
300   - hyzh:undefined,
301   - tkje:undefined,
302   - sgfy:undefined,
303   - bz:undefined,
304   - tkpx:undefined,
305   - tksj:new Date(),
306   - tkr:undefined,
307   - fileUrl:undefined,
308   - lqHytkJksyjList:[],
309   - lqHytkKjbsyjList:[],
310   - lqHytkMxList:[],
311   - },
312   - rules: {
313   - md: [
314   - { required: true, message: '请选择门店', trigger: 'change' }
315   - ],
316   - hy: [
317   - { required: true, message: '请选择会员', trigger: 'change' }
318   - ]
319   - },
320   - mdOptions : [],
321   - hyOptions : [],
322   - pxOptions : [],
323   - jksOptions:[],
324   - kjbOptions:[],
  330 +import request from '@/utils/request'
  331 +import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
  332 +import { previewDataInterface } from '@/api/systemData/dataInterface'
  333 +import { getInfo } from '@/api/user'
  334 +export default {
  335 + components: {},
  336 + props: [],
  337 + data() {
  338 + return {
  339 + loading: false,
  340 + visible: false,
  341 + isDetail: false,
  342 + dataForm: {
  343 + id: '',
  344 + id: undefined,
  345 + md: undefined,
  346 + mdbh: undefined,
  347 + mdmc: undefined,
  348 + hy: undefined,
  349 + hymc: undefined,
  350 + hyzh: undefined,
  351 + tkje: undefined,
  352 + sgfy: undefined,
  353 + bz: undefined,
  354 + tkpx: undefined,
  355 + tksj: new Date(),
  356 + tkr: undefined,
  357 + fileUrl: undefined,
  358 + lqHytkJksyjList: [],
  359 + lqHytkKjbsyjList: [],
  360 + lqHytkMxList: [],
  361 + },
  362 + rules: {
  363 + md: [
  364 + { required: true, message: '请选择门店', trigger: 'change' }
  365 + ],
  366 + hy: [
  367 + { required: true, message: '请选择会员', trigger: 'change' }
  368 + ]
  369 + },
  370 + mdOptions: [],
  371 + hyOptions: [],
  372 + pxOptions: [],
  373 + jksOptions: [],
  374 + kjbOptions: [],
  375 + }
  376 + },
  377 + computed: {},
  378 + watch: {},
  379 + created() {
  380 + // 门店数据在loadStoreDataAndSetDefault中加载,避免重复
  381 + this.gethyOptions();
  382 + this.getpxOptions();
  383 + },
  384 + mounted() {
  385 + },
  386 + methods: {
  387 + // 门店选择变化处理
  388 + handleMdChange(val) {
  389 + const selectedMd = this.mdOptions.find(item => item.id === val);
  390 + if (selectedMd) {
  391 + this.dataForm.mdbh = selectedMd.mdbh || selectedMd.id;
  392 + this.dataForm.mdmc = selectedMd.fullName;
  393 + console.log('选择门店:', selectedMd);
  394 + } else {
  395 + this.dataForm.mdbh = '';
  396 + this.dataForm.mdmc = '';
325 397 }
326 398 },
327   - computed: {},
328   - watch: {},
329   - created() {
330   - // 门店数据在loadStoreDataAndSetDefault中加载,避免重复
331   - this.gethyOptions();
332   - this.getpxOptions();
  399 + // 会员选择变化处理
  400 + handleHyChange(val) {
  401 + const selectedHy = this.hyOptions.find(item => item.id === val);
  402 + if (selectedHy) {
  403 + this.dataForm.hyzh = selectedHy.hyzh || selectedHy.id;
  404 + this.dataForm.hymc = selectedHy.fullName;
  405 + console.log('选择会员:', selectedHy);
  406 +
  407 + // 清空已选择的品项列表
  408 + this.dataForm.lqHytkMxList = [];
  409 +
  410 + // 选择会员后,获取该会员的剩余品项
  411 + this.getpxOptions();
  412 + } else {
  413 + this.dataForm.hyzh = '';
  414 + this.dataForm.hymc = '';
  415 + this.pxOptions = []; // 清空品项选项
  416 + this.dataForm.lqHytkMxList = []; // 清空已选择的品项列表
  417 +
  418 + // 重新计算总金额和总手工费
  419 + this.calculateTotalAmount();
  420 + this.calculateTotalLaborCost();
  421 + }
333 422 },
334   - mounted() {
335   - },
336   - methods: {
337   - // 门店选择变化处理
338   - handleMdChange(val) {
339   - const selectedMd = this.mdOptions.find(item => item.id === val);
340   - if (selectedMd) {
341   - this.dataForm.mdbh = selectedMd.mdbh || selectedMd.id;
342   - this.dataForm.mdmc = selectedMd.fullName;
343   - console.log('选择门店:', selectedMd);
344   - } else {
345   - this.dataForm.mdbh = '';
346   - this.dataForm.mdmc = '';
347   - }
348   - },
349   - // 会员选择变化处理
350   - handleHyChange(val) {
351   - const selectedHy = this.hyOptions.find(item => item.id === val);
352   - if (selectedHy) {
353   - this.dataForm.hyzh = selectedHy.hyzh || selectedHy.id;
354   - this.dataForm.hymc = selectedHy.fullName;
355   - console.log('选择会员:', selectedHy);
356   -
357   - // 清空已选择的品项列表
358   - this.dataForm.lqHytkMxList = [];
359   -
360   - // 选择会员后,获取该会员的剩余品项
361   - this.getpxOptions();
362   - } else {
363   - this.dataForm.hyzh = '';
364   - this.dataForm.hymc = '';
365   - this.pxOptions = []; // 清空品项选项
366   - this.dataForm.lqHytkMxList = []; // 清空已选择的品项列表
367   -
368   - // 重新计算总金额和总手工费
369   - this.calculateTotalAmount();
370   - this.calculateTotalLaborCost();
371   - }
372   - },
373   - // 品项选择变化处理
374   - handlePxChange(index, row) {
375   - if (row.pxid) {
376   - const selectedPx = this.pxOptions.find(item => item.pxid === row.pxid);
377   - if (selectedPx) {
378   - request({
379   - url: `/api/Extend/LqXmzl/${selectedPx.id}`,
380   - method: 'GET',
381   - }).then((res) => {
382   - let qt2 = res.data.qt2 || "";
383   - let sgf = res.data.sgf || 0;
384   - row.px = selectedPx.id;
385   - row.pxmc = selectedPx.fullName;
386   - row.pxjg = selectedPx.ItemPrice || 0;
387   - row.qt2 = qt2 || "";
388   - row.yxf = selectedPx.ConsumedCount || 0; // 已消费
389   - row.zgm = selectedPx.TotalPurchased || 1; // 总购买
390   - row.ly = selectedPx.sourceType || "购买"; // 来源
391   - row.projectNumber = 1; // 默认消费数量为1
392   - row.sgf = sgf;
393   -
394   - // 品项切换时,清空所有人员列表
395   - row.lqHytkJksyjList = []; // 清空健康师列表
396   - row.lqHytkKjbsyjList = []; // 清空科技部老师列表
397   -
398   - console.log('选择品项:', selectedPx.fullName, 'qt2:', selectedPx.qt2, '剩余数量:', selectedPx.RemainingCount, '手工费:', sgf);
399   -
400   - // 重新计算总金额和总手工费
401   - this.calculateTotalAmount();
402   - this.calculateTotalLaborCost();
403   - })
404   - }
405   - } else {
406   - // 清空品项时,重置所有相关字段
407   - row.pxmc = '';
408   - row.pxjg = 0;
409   - row.qt2 = '';
410   - row.yxf = 0;
411   - row.zgm = 1;
412   - row.ly = '购买';
413   - row.projectNumber = 1;
414   - row.sgf = 0; // 清空手工费
415   - row.lqHytkJksyjList = []; // 清空健康师列表
416   - row.lqHytkKjbsyjList = []; // 清空科技部老师列表
417   -
418   - // 重新计算总金额和总手工费
419   - this.calculateTotalAmount();
420   - this.calculateTotalLaborCost();
421   - }
422   - },
423   - getmdOptions(){
424   - previewDataInterface('730960205902251269').then(res => {
425   - this.mdOptions = res.data
426   - });
427   - },
428   - gethyOptions(){
429   - previewDataInterface('730998109110273285').then(res => {
430   - this.hyOptions = res.data
431   - });
432   - },
433   - // 获取品项选项(从会员剩余品项API获取)
434   - async getpxOptions() {
435   - if (!this.dataForm.hy) {
436   - console.warn("请先选择会员");
437   - this.pxOptions = [];
438   - return;
  423 + // 品项选择变化处理
  424 + handlePxChange(index, row) {
  425 + if (row.pxid) {
  426 + const selectedPx = this.pxOptions.find(item => item.pxid === row.pxid);
  427 + if (selectedPx) {
  428 + request({
  429 + url: `/api/Extend/LqXmzl/${selectedPx.id}`,
  430 + method: 'GET',
  431 + }).then((res) => {
  432 + let qt2 = res.data.qt2 || "";
  433 + let sgf = res.data.sgf || 0;
  434 + row.px = selectedPx.id;
  435 + row.pxmc = selectedPx.fullName;
  436 + row.pxjg = selectedPx.ItemPrice || 0;
  437 + row.qt2 = qt2 || "";
  438 + row.yxf = selectedPx.ConsumedCount || 0; // 已消费
  439 + row.zgm = selectedPx.TotalPurchased || 1; // 总购买
  440 + row.ly = selectedPx.sourceType || "购买"; // 来源
  441 + row.projectNumber = 1; // 默认消费数量为1
  442 + row.sgf = sgf;
  443 +
  444 + // 品项切换时,清空所有人员列表
  445 + row.lqHytkJksyjList = []; // 清空健康师列表
  446 + row.lqHytkKjbsyjList = []; // 清空科技部老师列表
  447 +
  448 + console.log('选择品项:', selectedPx.fullName, 'qt2:', selectedPx.qt2, '剩余数量:', selectedPx.RemainingCount, '手工费:', sgf);
  449 +
  450 + // 重新计算总金额和总手工费
  451 + this.calculateTotalAmount();
  452 + this.calculateTotalLaborCost();
  453 + })
439 454 }
  455 + } else {
  456 + // 清空品项时,重置所有相关字段
  457 + row.pxmc = '';
  458 + row.pxjg = 0;
  459 + row.qt2 = '';
  460 + row.yxf = 0;
  461 + row.zgm = 1;
  462 + row.ly = '购买';
  463 + row.projectNumber = 1;
  464 + row.sgf = 0; // 清空手工费
  465 + row.lqHytkJksyjList = []; // 清空健康师列表
  466 + row.lqHytkKjbsyjList = []; // 清空科技部老师列表
440 467  
441   - try {
442   - const response = await request({
443   - url: `/api/Extend/lqkhxx/GetMemberRemainingItems?memberId=${this.dataForm.hy}`,
444   - method: 'GET',
445   - });
  468 + // 重新计算总金额和总手工费
  469 + this.calculateTotalAmount();
  470 + this.calculateTotalLaborCost();
  471 + }
  472 + },
  473 + getmdOptions() {
  474 + previewDataInterface('730960205902251269').then(res => {
  475 + this.mdOptions = res.data
  476 + });
  477 + },
  478 + gethyOptions() {
  479 + previewDataInterface('730998109110273285').then(res => {
  480 + this.hyOptions = res.data
  481 + });
  482 + },
  483 + // 获取品项选项(从会员剩余品项API获取)
  484 + async getpxOptions() {
  485 + if (!this.dataForm.hy) {
  486 + console.warn("请先选择会员");
  487 + this.pxOptions = [];
  488 + return;
  489 + }
446 490  
447   - if (response.code == 200 && response.data && response.data.RemainingItems) {
448   - this.pxOptions = response.data.RemainingItems.map(item => ({
449   - fullName: item.ItemName,
450   - id: item.ItemId,
451   - value: item.ItemId,
452   - label: item.ItemName,
453   - px: item.ItemId,
454   - pxmc: item.ItemName,
455   - pxjg: item.ItemPrice || 0,
456   - qt2: item.qt2 || "",
457   - RemainingCount: item.RemainingCount || 0,
458   - ItemPrice: item.ItemPrice || 0,
459   - sgf: 0,
460   - sourceType: item.SourceType || "购买",
461   - TotalPurchased: item.TotalPurchased || 0,
462   - ConsumedCount: item.ConsumedCount || 0,
463   - pxid: item.ItemId+','+item.SourceType
464   - }));
465   - console.log('获取会员剩余品项成功:', this.pxOptions);
466   - } else {
467   - console.warn("获取会员剩余品项失败,使用默认数据");
468   - this.pxOptions = [];
469   - }
470   - } catch (error) {
471   - console.error("获取会员剩余品项出错:", error);
472   - this.pxOptions = [];
473   - }
474   - },
475   - // 获取健康师选项
476   - getjksOptions() {
477   - request({
478   - url: `/api/Extend/user?page=1&pageSize=1000&mdid=${this.dataForm.md}&gw=健康师`,
479   - method: 'GET',
480   - }).then((res) => {
481   - if (res.code == 200 && res.data.list.length > 0) {
482   - this.jksOptions = res.data.list.map(item => ({
483   - fullName: item.realName || item.name || item.userName,
484   - id: item.id,
485   - value: item.id,
486   - label: item.realName || item.name || item.userName,
487   - jks: item.id,
488   - jksxm: item.realName || item.name || item.userName,
489   - jkszh: item.mobilePhone || item.account || item.userName
490   - }));
491   - } else {
492   - this.jksOptions = [];
493   - }
494   - })
495   - },
496   - // 获取科技部老师选项
497   - async getkjbOptions() {
498   - await this.getKjbOptionsByOrganizeId();
499   - },
500   - // 根据门店ID获取科技部组织ID,再获取科技部老师列表
501   - async getKjbOptionsByOrganizeId() {
502   - const userResponse = await request({
503   - url: `/api/Extend/user?page=1&pageSize=1000&gw=科技老师`,
  491 + try {
  492 + const response = await request({
  493 + url: `/api/Extend/lqkhxx/GetMemberRemainingItems?memberId=${this.dataForm.hy}`,
504 494 method: 'GET',
505 495 });
506   -
507   - if (userResponse.code == 200 && userResponse.data && userResponse.data.list.length > 0) {
508   - this.kjbOptions = userResponse.data.list.map(item => ({
  496 +
  497 + if (response.code == 200 && response.data && response.data.RemainingItems) {
  498 + this.pxOptions = response.data.RemainingItems.map(item => ({
  499 + fullName: item.ItemName,
  500 + id: item.ItemId,
  501 + value: item.ItemId,
  502 + label: item.ItemName,
  503 + px: item.ItemId,
  504 + pxmc: item.ItemName,
  505 + pxjg: item.ItemPrice || 0,
  506 + qt2: item.qt2 || "",
  507 + RemainingCount: item.RemainingCount || 0,
  508 + ItemPrice: item.ItemPrice || 0,
  509 + sgf: 0,
  510 + sourceType: item.SourceType || "购买",
  511 + TotalPurchased: item.TotalPurchased || 0,
  512 + ConsumedCount: item.ConsumedCount || 0,
  513 + pxid: item.ItemId + ',' + item.SourceType
  514 + }));
  515 + console.log('获取会员剩余品项成功:', this.pxOptions);
  516 + } else {
  517 + console.warn("获取会员剩余品项失败,使用默认数据");
  518 + this.pxOptions = [];
  519 + }
  520 + } catch (error) {
  521 + console.error("获取会员剩余品项出错:", error);
  522 + this.pxOptions = [];
  523 + }
  524 + },
  525 + // 获取健康师选项
  526 + getjksOptions() {
  527 + request({
  528 + url: `/api/Extend/user?page=1&pageSize=1000&mdid=${this.dataForm.md}&gw=健康师`,
  529 + method: 'GET',
  530 + }).then((res) => {
  531 + if (res.code == 200 && res.data.list.length > 0) {
  532 + this.jksOptions = res.data.list.map(item => ({
509 533 fullName: item.realName || item.name || item.userName,
510 534 id: item.id,
511 535 value: item.id,
512 536 label: item.realName || item.name || item.userName,
513   - kjbls: item.id,
514   - kjblsxm: item.realName || item.name || item.userName,
515   - kjblszh: item.mobilePhone || item.account || item.userName
  537 + jks: item.id,
  538 + jksxm: item.realName || item.name || item.userName,
  539 + jkszh: item.mobilePhone || item.account || item.userName
516 540 }));
517   - console.log('科技部老师列表:', this.kjbOptions);
518 541 } else {
519   - console.warn('获取科技部老师列表失败');
520   - this.kjbOptions = [];
  542 + this.jksOptions = [];
521 543 }
522   - },
523   - // 品项健康师选择
524   - handleJksChange(pxIndex, jksIndex, row) {
525   - console.log('品项健康师选择:', row);
526   - if (row.jks) {
527   - // 根据选择的健康师ID获取用户信息
528   - const selectedJks = this.jksOptions.find(item => item.id === row.jks);
529   - if (selectedJks) {
530   - // 填充姓名和账号
531   - row.jksxm = selectedJks.fullName;
532   - row.jkszh = selectedJks.userName || selectedJks.account || selectedJks.id;
533   -
534   - // 获取金三角信息
535   - this.getJsjInfoByUserId(row.jks, (jsjId, jsjName) => {
536   - row.jsjName = jsjName;
537   - row.jsjId = jsjId;
538   - });
539   - }
540   - } else {
541   - // 清空相关字段
542   - row.jksxm = '';
543   - row.jkszh = '';
544   - row.jsjId = '';
  544 + })
  545 + },
  546 + // 获取科技部老师选项
  547 + async getkjbOptions() {
  548 + await this.getKjbOptionsByOrganizeId();
  549 + },
  550 + // 根据门店ID获取科技部组织ID,再获取科技部老师列表
  551 + async getKjbOptionsByOrganizeId() {
  552 + const userResponse = await request({
  553 + url: `/api/Extend/user?page=1&pageSize=1000&gw=科技老师`,
  554 + method: 'GET',
  555 + });
  556 +
  557 + if (userResponse.code == 200 && userResponse.data && userResponse.data.list.length > 0) {
  558 + this.kjbOptions = userResponse.data.list.map(item => ({
  559 + fullName: item.realName || item.name || item.userName,
  560 + id: item.id,
  561 + value: item.id,
  562 + label: item.realName || item.name || item.userName,
  563 + kjbls: item.id,
  564 + kjblsxm: item.realName || item.name || item.userName,
  565 + kjblszh: item.mobilePhone || item.account || item.userName
  566 + }));
  567 + console.log('科技部老师列表:', this.kjbOptions);
  568 + } else {
  569 + console.warn('获取科技部老师列表失败');
  570 + this.kjbOptions = [];
  571 + }
  572 + },
  573 + // 品项健康师选择
  574 + handleJksChange(pxIndex, jksIndex, row) {
  575 + console.log('品项健康师选择:', row);
  576 + if (row.jks) {
  577 + // 根据选择的健康师ID获取用户信息
  578 + const selectedJks = this.jksOptions.find(item => item.id === row.jks);
  579 + if (selectedJks) {
  580 + // 填充姓名和账号
  581 + row.jksxm = selectedJks.fullName;
  582 + row.jkszh = selectedJks.userName || selectedJks.account || selectedJks.id;
  583 +
  584 + // 获取金三角信息
  585 + this.getJsjInfoByUserId(row.jks, (jsjId, jsjName) => {
  586 + row.jsjName = jsjName;
  587 + row.jsjId = jsjId;
  588 + });
545 589 }
546   - },
547   - // 品项科技部老师选择
548   - handleKjbChange(pxIndex, kjbIndex, row) {
549   - console.log('品项科技部老师选择:', row);
550   - if (row.kjbls) {
551   - // 根据选择的科技部老师ID获取用户信息
552   - const selectedKjb = this.kjbOptions.find(item => item.id === row.kjbls);
553   - if (selectedKjb) {
554   - // 填充姓名和账号
555   - row.kjblsxm = selectedKjb.fullName;
556   - row.kjblszh = selectedKjb.userName || selectedKjb.account || selectedKjb.id;
557   - }
558   - } else {
559   - // 清空相关字段
560   - row.kjblsxm = '';
561   - row.kjblszh = '';
  590 + } else {
  591 + // 清空相关字段
  592 + row.jksxm = '';
  593 + row.jkszh = '';
  594 + row.jsjId = '';
  595 + }
  596 + },
  597 + // 品项科技部老师选择
  598 + handleKjbChange(pxIndex, kjbIndex, row) {
  599 + console.log('品项科技部老师选择:', row);
  600 + if (row.kjbls) {
  601 + // 根据选择的科技部老师ID获取用户信息
  602 + const selectedKjb = this.kjbOptions.find(item => item.id === row.kjbls);
  603 + if (selectedKjb) {
  604 + // 填充姓名和账号
  605 + row.kjblsxm = selectedKjb.fullName;
  606 + row.kjblszh = selectedKjb.userName || selectedKjb.account || selectedKjb.id;
562 607 }
563   - },
564   - // 格式化日期方法
  608 + } else {
  609 + // 清空相关字段
  610 + row.kjblsxm = '';
  611 + row.kjblszh = '';
  612 + }
  613 + },
  614 + // 格式化日期方法
565 615 formatDate(date, format) {
566 616 if (!date) return '';
567 617 const d = new Date(date);
... ... @@ -571,7 +621,7 @@
571 621 const hours = String(d.getHours()).padStart(2, '0');
572 622 const minutes = String(d.getMinutes()).padStart(2, '0');
573 623 const seconds = String(d.getSeconds()).padStart(2, '0');
574   -
  624 +
575 625 return format
576 626 .replace('yyyy', year)
577 627 .replace('MM', month)
... ... @@ -580,629 +630,629 @@
580 630 .replace('mm', minutes)
581 631 .replace('ss', seconds);
582 632 },
583   - // 根据用户ID获取金三角信息
584   - getJsjInfoByUserId(userId, callback) {
585   - let date = new Date(this.dataForm.tksj);
586   - let formattedDate = this.formatDate(date, 'yyyy-MM-dd HH:mm:ss');
587   - console.log('formattedDate:', formattedDate);
588   - request({
589   - url: `/api/Extend/lqycsdjsj/GetJsjInfoByUserMonth?UserId=${userId}&DateTime=${formattedDate}`,
590   - method: 'GET',
591   - }).then((res) => {
592   - if (res.code === 200 && res.data) {
593   - // 假设返回的数据结构中有jsj_id字段
594   - const jsjId = res.data.jsjId;
595   - const jsjName = res.data.jsjName;
596   -
597   - if (callback) {
598   - callback(jsjId, jsjName);
599   - }
600   - console.log('获取金三角信息成功:', res.data);
601   - } else {
602   - console.warn('获取金三角信息失败:', res.msg);
603   - if (callback) {
604   - callback('');
605   - }
  633 + // 根据用户ID获取金三角信息
  634 + getJsjInfoByUserId(userId, callback) {
  635 + let date = new Date(this.dataForm.tksj);
  636 + let formattedDate = this.formatDate(date, 'yyyy-MM-dd HH:mm:ss');
  637 + console.log('formattedDate:', formattedDate);
  638 + request({
  639 + url: `/api/Extend/lqycsdjsj/GetJsjInfoByUserMonth?UserId=${userId}&DateTime=${formattedDate}`,
  640 + method: 'GET',
  641 + }).then((res) => {
  642 + if (res.code === 200 && res.data) {
  643 + // 假设返回的数据结构中有jsj_id字段
  644 + const jsjId = res.data.jsjId;
  645 + const jsjName = res.data.jsjName;
  646 +
  647 + if (callback) {
  648 + callback(jsjId, jsjName);
606 649 }
607   - }).catch((err) => {
608   - console.error('获取金三角信息出错:', err);
  650 + console.log('获取金三角信息成功:', res.data);
  651 + } else {
  652 + console.warn('获取金三角信息失败:', res.msg);
609 653 if (callback) {
610 654 callback('');
611 655 }
612   - });
613   - },
614   - // 品项内人员业绩数字格式化
615   - formatPxStaffNumber(pxIndex, staffIndex, field, listName) {
616   - const targetList = this.dataForm.lqHytkMxList[pxIndex][listName];
617   - if (targetList && targetList[staffIndex] && targetList[staffIndex][field] !== undefined) {
618   - let value = targetList[staffIndex][field].toString().replace(/,/g, '');
619   -
620   - if (!/^\d*\.?\d*$/.test(value)) {
621   - value = value.replace(/[^\d.]/g, '');
622   - }
623   -
624   - targetList[staffIndex][field] = value;
625 656 }
626   - },
627   - // 获取品项剩余数量
628   - getRemainingCount(px) {
629   - if (px.px) {
630   - const selectedPx = this.pxOptions.find(item => item.id === px.px);
631   - if (selectedPx) {
632   - return selectedPx.RemainingCount || 0;
633   - }
  657 + }).catch((err) => {
  658 + console.error('获取金三角信息出错:', err);
  659 + if (callback) {
  660 + callback('');
634 661 }
635   - return (px.zgm || 1) - (px.yxf || 0);
636   - },
637   - // 消费数量变化处理
638   - onProjectNumberChange() {
639   - // 重新计算总金额和总手工费
640   - this.calculateTotalAmount();
641   - this.calculateTotalLaborCost();
642   - },
643   - // 品项消费数量变化处理(带参数)
644   - onPxProjectNumberChange(pxIndex, projectNumber) {
645   - // 更新品项的消费数量
646   - this.dataForm.lqHytkMxList[pxIndex].projectNumber = projectNumber;
647   -
648   - // 获取当前品项的手工费
649   - const currentPx = this.dataForm.lqHytkMxList[pxIndex];
650   - const laborCost = currentPx.sgf || 0;
651   -
652   - // 更新该品项下所有人员的手工费
653   - this.updatePxStaffLaborCost(pxIndex, laborCost);
654   -
655   - // 重新计算总金额和总手工费
656   - this.calculateTotalAmount();
657   - this.calculateTotalLaborCost();
658   - },
659   - // 更新品项下所有人员的手工费
660   - updatePxStaffLaborCost(pxIndex, newLaborCost) {
661   - const currentPx = this.dataForm.lqHytkMxList[pxIndex];
662   - console.log('更新品项手工费:', {
663   - pxIndex,
664   - newLaborCost,
665   - pxName: currentPx.pxmc,
666   - hasJks: currentPx.lqHytkJksyjList && currentPx.lqHytkJksyjList.length > 0,
667   - hasKjb: currentPx.lqHytkKjbsyjList && currentPx.lqHytkKjbsyjList.length > 0
668   - });
669   -
670   - // 更新健康师的手工费 = 品项手工费 × 健康师次数
671   - if (currentPx.lqHytkJksyjList && currentPx.lqHytkJksyjList.length > 0) {
672   - currentPx.lqHytkJksyjList.forEach((jks, index) => {
673   - const jksLaborCost = newLaborCost * (jks.kdpxNumber || 1);
674   - console.log(`更新健康师${index}手工费:`, jks.laborCost, '->', jksLaborCost, `(${newLaborCost} × ${jks.kdpxNumber || 1})`);
675   - // 使用Vue.set确保响应式更新
676   - this.$set(jks, 'laborCost', jksLaborCost);
677   - });
  662 + });
  663 + },
  664 + // 品项内人员业绩数字格式化
  665 + formatPxStaffNumber(pxIndex, staffIndex, field, listName) {
  666 + const targetList = this.dataForm.lqHytkMxList[pxIndex][listName];
  667 + if (targetList && targetList[staffIndex] && targetList[staffIndex][field] !== undefined) {
  668 + let value = targetList[staffIndex][field].toString().replace(/,/g, '');
  669 +
  670 + if (!/^\d*\.?\d*$/.test(value)) {
  671 + value = value.replace(/[^\d.]/g, '');
678 672 }
679   -
680   - // 更新科技部老师的手工费 = 品项手工费 × 科技部老师次数
681   - if (currentPx.lqHytkKjbsyjList && currentPx.lqHytkKjbsyjList.length > 0) {
682   - currentPx.lqHytkKjbsyjList.forEach((kjb, index) => {
683   - const kjbLaborCost = newLaborCost * (kjb.hdpxNumber || 1);
684   - console.log(`更新科技部老师${index}手工费:`, kjb.laborCost, '->', kjbLaborCost, `(${newLaborCost} × ${kjb.hdpxNumber || 1})`);
685   - // 使用Vue.set确保响应式更新
686   - this.$set(kjb, 'laborCost', kjbLaborCost);
687   - });
  673 +
  674 + targetList[staffIndex][field] = value;
  675 + }
  676 + },
  677 + // 获取品项剩余数量
  678 + getRemainingCount(px) {
  679 + if (px.px) {
  680 + const selectedPx = this.pxOptions.find(item => item.id === px.px);
  681 + if (selectedPx) {
  682 + return selectedPx.RemainingCount || 0;
688 683 }
689   - },
690   - // 健康师次数变化处理
691   - onJksNumberChange(pxIndex, jksIndex, newNumber) {
692   - const currentPx = this.dataForm.lqHytkMxList[pxIndex];
693   - const jks = currentPx.lqHytkJksyjList[jksIndex];
694   -
695   - // 更新健康师的次数
696   - this.$set(jks, 'kdpxNumber', newNumber);
697   -
698   - // 重新计算该健康师的手工费 = 品项手工费 × 健康师次数
699   - const pxLaborCost = currentPx.sgf || 0;
700   - const newJksLaborCost = pxLaborCost * newNumber;
701   - this.$set(jks, 'laborCost', newJksLaborCost);
702   -
703   - // 重新计算总金额和总手工费
704   - this.calculateTotalAmount();
705   - this.calculateTotalLaborCost();
706   -
707   - console.log('健康师次数变化:', {
708   - pxIndex,
709   - jksIndex,
710   - newNumber,
711   - jksName: jks.jksxm,
712   - pxLaborCost,
713   - newJksLaborCost,
714   - formula: `${pxLaborCost} × ${newNumber} = ${newJksLaborCost}`
715   - });
716   - },
717   - // 科技部老师次数变化处理
718   - onKjbNumberChange(pxIndex, kjbIndex, newNumber) {
719   - const currentPx = this.dataForm.lqHytkMxList[pxIndex];
720   - const kjb = currentPx.lqHytkKjbsyjList[kjbIndex];
721   -
722   - // 更新科技部老师的次数
723   - this.$set(kjb, 'hdpxNumber', newNumber);
724   -
725   - // 重新计算该科技部老师的手工费 = 品项手工费 × 科技部老师次数
726   - const pxLaborCost = currentPx.sgf || 0;
727   - const newKjbLaborCost = pxLaborCost * newNumber;
728   - this.$set(kjb, 'laborCost', newKjbLaborCost);
729   -
730   - // 重新计算总金额和总手工费
731   - this.calculateTotalAmount();
732   - this.calculateTotalLaborCost();
733   -
734   - console.log('科技部老师次数变化:', {
735   - pxIndex,
736   - kjbIndex,
737   - newNumber,
738   - kjbName: kjb.kjblsxm,
739   - pxLaborCost,
740   - newKjbLaborCost,
741   - formula: `${pxLaborCost} × ${newNumber} = ${newKjbLaborCost}`
  684 + }
  685 + return (px.zgm || 1) - (px.yxf || 0);
  686 + },
  687 + // 消费数量变化处理
  688 + onProjectNumberChange() {
  689 + // 重新计算总金额和总手工费
  690 + this.calculateTotalAmount();
  691 + this.calculateTotalLaborCost();
  692 + },
  693 + // 品项消费数量变化处理(带参数)
  694 + onPxProjectNumberChange(pxIndex, projectNumber) {
  695 + // 更新品项的消费数量
  696 + this.dataForm.lqHytkMxList[pxIndex].projectNumber = projectNumber;
  697 +
  698 + // 获取当前品项的手工费
  699 + const currentPx = this.dataForm.lqHytkMxList[pxIndex];
  700 + const laborCost = currentPx.sgf || 0;
  701 +
  702 + // 更新该品项下所有人员的手工费
  703 + this.updatePxStaffLaborCost(pxIndex, laborCost);
  704 +
  705 + // 重新计算总金额和总手工费
  706 + this.calculateTotalAmount();
  707 + this.calculateTotalLaborCost();
  708 + },
  709 + // 更新品项下所有人员的手工费
  710 + updatePxStaffLaborCost(pxIndex, newLaborCost) {
  711 + const currentPx = this.dataForm.lqHytkMxList[pxIndex];
  712 + console.log('更新品项手工费:', {
  713 + pxIndex,
  714 + newLaborCost,
  715 + pxName: currentPx.pxmc,
  716 + hasJks: currentPx.lqHytkJksyjList && currentPx.lqHytkJksyjList.length > 0,
  717 + hasKjb: currentPx.lqHytkKjbsyjList && currentPx.lqHytkKjbsyjList.length > 0
  718 + });
  719 +
  720 + // 更新健康师的手工费 = 品项手工费 × 健康师次数
  721 + if (currentPx.lqHytkJksyjList && currentPx.lqHytkJksyjList.length > 0) {
  722 + currentPx.lqHytkJksyjList.forEach((jks, index) => {
  723 + const jksLaborCost = newLaborCost * (jks.kdpxNumber || 1);
  724 + console.log(`更新健康师${index}手工费:`, jks.laborCost, '->', jksLaborCost, `(${newLaborCost} × ${jks.kdpxNumber || 1})`);
  725 + // 使用Vue.set确保响应式更新
  726 + this.$set(jks, 'laborCost', jksLaborCost);
742 727 });
743   - },
744   - // 计算总退款金额
745   - calculateTotalAmount() {
746   - let totalAmount = 0;
747   - this.dataForm.lqHytkMxList.forEach(px => {
748   - if (px.px && px.pxjg && px.projectNumber) {
749   - totalAmount += parseFloat(px.pxjg) * parseInt(px.projectNumber);
750   - }
  728 + }
  729 +
  730 + // 更新科技部老师的手工费 = 品项手工费 × 科技部老师次数
  731 + if (currentPx.lqHytkKjbsyjList && currentPx.lqHytkKjbsyjList.length > 0) {
  732 + currentPx.lqHytkKjbsyjList.forEach((kjb, index) => {
  733 + const kjbLaborCost = newLaborCost * (kjb.hdpxNumber || 1);
  734 + console.log(`更新科技部老师${index}手工费:`, kjb.laborCost, '->', kjbLaborCost, `(${newLaborCost} × ${kjb.hdpxNumber || 1})`);
  735 + // 使用Vue.set确保响应式更新
  736 + this.$set(kjb, 'laborCost', kjbLaborCost);
751 737 });
752   - this.dataForm.tkje = totalAmount.toFixed(2);
753   - },
754   - // 计算总手工费
755   - calculateTotalLaborCost() {
756   - let totalLaborCost = 0;
757   - this.dataForm.lqHytkMxList.forEach(px => {
758   - // 只计算品项的手工费 = 品项单次手工费 × 品项消费次数
759   - if (px.sgf && px.projectNumber) {
760   - totalLaborCost += parseFloat(px.sgf) * parseInt(px.projectNumber);
  738 + }
  739 + },
  740 + // 健康师次数变化处理
  741 + onJksNumberChange(pxIndex, jksIndex, newNumber) {
  742 + const currentPx = this.dataForm.lqHytkMxList[pxIndex];
  743 + const jks = currentPx.lqHytkJksyjList[jksIndex];
  744 +
  745 + // 更新健康师的次数
  746 + this.$set(jks, 'kdpxNumber', newNumber);
  747 +
  748 + // 重新计算该健康师的手工费 = 品项手工费 × 健康师次数
  749 + const pxLaborCost = currentPx.sgf || 0;
  750 + const newJksLaborCost = pxLaborCost * newNumber;
  751 + this.$set(jks, 'laborCost', newJksLaborCost);
  752 +
  753 + // 重新计算总金额和总手工费
  754 + this.calculateTotalAmount();
  755 + this.calculateTotalLaborCost();
  756 +
  757 + console.log('健康师次数变化:', {
  758 + pxIndex,
  759 + jksIndex,
  760 + newNumber,
  761 + jksName: jks.jksxm,
  762 + pxLaborCost,
  763 + newJksLaborCost,
  764 + formula: `${pxLaborCost} × ${newNumber} = ${newJksLaborCost}`
  765 + });
  766 + },
  767 + // 科技部老师次数变化处理
  768 + onKjbNumberChange(pxIndex, kjbIndex, newNumber) {
  769 + const currentPx = this.dataForm.lqHytkMxList[pxIndex];
  770 + const kjb = currentPx.lqHytkKjbsyjList[kjbIndex];
  771 +
  772 + // 更新科技部老师的次数
  773 + this.$set(kjb, 'hdpxNumber', newNumber);
  774 +
  775 + // 重新计算该科技部老师的手工费 = 品项手工费 × 科技部老师次数
  776 + const pxLaborCost = currentPx.sgf || 0;
  777 + const newKjbLaborCost = pxLaborCost * newNumber;
  778 + this.$set(kjb, 'laborCost', newKjbLaborCost);
  779 +
  780 + // 重新计算总金额和总手工费
  781 + this.calculateTotalAmount();
  782 + this.calculateTotalLaborCost();
  783 +
  784 + console.log('科技部老师次数变化:', {
  785 + pxIndex,
  786 + kjbIndex,
  787 + newNumber,
  788 + kjbName: kjb.kjblsxm,
  789 + pxLaborCost,
  790 + newKjbLaborCost,
  791 + formula: `${pxLaborCost} × ${newNumber} = ${newKjbLaborCost}`
  792 + });
  793 + },
  794 + // 计算总退款金额
  795 + calculateTotalAmount() {
  796 + let totalAmount = 0;
  797 + this.dataForm.lqHytkMxList.forEach(px => {
  798 + if (px.px && px.pxjg && px.projectNumber) {
  799 + totalAmount += parseFloat(px.pxjg) * parseInt(px.projectNumber);
  800 + }
  801 + });
  802 + this.dataForm.tkje = totalAmount.toFixed(2);
  803 + },
  804 + // 计算总手工费
  805 + calculateTotalLaborCost() {
  806 + let totalLaborCost = 0;
  807 + this.dataForm.lqHytkMxList.forEach(px => {
  808 + // 只计算品项的手工费 = 品项单次手工费 × 品项消费次数
  809 + if (px.sgf && px.projectNumber) {
  810 + totalLaborCost += parseFloat(px.sgf) * parseInt(px.projectNumber);
  811 + }
  812 + });
  813 + this.dataForm.sgfy = totalLaborCost.toFixed(2);
  814 + console.log('计算总手工费(仅品项):', totalLaborCost, '各品项手工费:', this.dataForm.lqHytkMxList.map(px => ({
  815 + name: px.pxmc,
  816 + sgf: px.sgf,
  817 + projectNumber: px.projectNumber,
  818 + total: parseFloat(px.sgf || 0) * parseInt(px.projectNumber || 0)
  819 + })));
  820 + },
  821 + goBack() {
  822 + this.$emit('refresh')
  823 + },
  824 + init(id, isDetail) {
  825 + this.dataForm.id = id || 0;
  826 + this.visible = true;
  827 + this.isDetail = isDetail || false;
  828 + this.$nextTick(() => {
  829 + this.$refs['elForm'].resetFields();
  830 + if (this.dataForm.id) {
  831 + request({
  832 + url: '/api/Extend/LqHytkHytk/' + this.dataForm.id,
  833 + method: 'get'
  834 + }).then(res => {
  835 + this.dataForm = res.data;
  836 + this.dataForm.fileUrl = this.dataForm.fileUrl ? JSON.parse(this.dataForm.fileUrl) : [];
  837 + })
  838 + } else {
  839 + // 新建时自动设置当前用户门店
  840 + this.loadStoreDataAndSetDefault();
  841 + // 加载健康师和科技部老师选项
  842 + this.getjksOptions();
  843 + this.getkjbOptions();
  844 + // 初始化时计算总金额和总手工费
  845 + this.calculateTotalAmount();
  846 + this.calculateTotalLaborCost();
  847 + }
  848 + })
  849 + },
  850 + dataFormSubmit() {
  851 +
  852 + this.$refs['elForm'].validate((valid) => {
  853 + if (valid) {
  854 + // 验证品项数据
  855 + if (!this.validatePxList()) {
  856 + return;
761 857 }
762   - });
763   - this.dataForm.sgfy = totalLaborCost.toFixed(2);
764   - console.log('计算总手工费(仅品项):', totalLaborCost, '各品项手工费:', this.dataForm.lqHytkMxList.map(px => ({
765   - name: px.pxmc,
766   - sgf: px.sgf,
767   - projectNumber: px.projectNumber,
768   - total: parseFloat(px.sgf || 0) * parseInt(px.projectNumber || 0)
769   - })));
770   - },
771   - goBack() {
772   - this.$emit('refresh')
773   - },
774   - init(id, isDetail) {
775   - this.dataForm.id = id || 0;
776   - this.visible = true;
777   - this.isDetail = isDetail || false;
778   - this.$nextTick(() => {
779   - this.$refs['elForm'].resetFields();
780   - if (this.dataForm.id) {
  858 +
  859 + // 处理提交格式
  860 + this.processFormData();
  861 + console.log(this.dataForm)
  862 + // return
  863 +
  864 + this.dataForm.fileUrl = JSON.stringify(this.dataForm.fileUrl);
  865 + if (!this.dataForm.id) {
781 866 request({
782   - url: '/api/Extend/LqHytkHytk/' + this.dataForm.id,
783   - method: 'get'
784   - }).then(res =>{
785   - this.dataForm = res.data;
786   - this.dataForm.fileUrl = this.dataForm.fileUrl?JSON.parse(this.dataForm.fileUrl):[];
  867 + url: `/api/Extend/LqHytkHytk`,
  868 + method: 'post',
  869 + data: this.dataForm,
  870 + }).then((res) => {
  871 + this.$message({
  872 + message: res.msg,
  873 + type: 'success',
  874 + duration: 1000,
  875 + onClose: () => {
  876 + this.visible = false,
  877 + this.$emit('refresh', true)
  878 + }
  879 + })
787 880 })
788 881 } else {
789   - // 新建时自动设置当前用户门店
790   - this.loadStoreDataAndSetDefault();
791   - // 加载健康师和科技部老师选项
792   - this.getjksOptions();
793   - this.getkjbOptions();
794   - // 初始化时计算总金额和总手工费
795   - this.calculateTotalAmount();
796   - this.calculateTotalLaborCost();
  882 + request({
  883 + url: '/api/Extend/LqHytkHytk/' + this.dataForm.id,
  884 + method: 'PUT',
  885 + data: this.dataForm
  886 + }).then((res) => {
  887 + this.$message({
  888 + message: res.msg,
  889 + type: 'success',
  890 + duration: 1000,
  891 + onClose: () => {
  892 + this.visible = false
  893 + this.$emit('refresh', true)
  894 + }
  895 + })
  896 + })
797 897 }
798   - })
799   - },
800   - dataFormSubmit() {
801   -
802   - this.$refs['elForm'].validate((valid) => {
803   - if (valid) {
804   - // 验证品项数据
805   - if (!this.validatePxList()) {
806   - return;
807   - }
  898 + }
  899 + })
  900 + },
  901 + // 品项相关方法
  902 + addHandleLqXhPxmxEntityList() {
  903 + let item = {
  904 + id: undefined,
  905 + glkdbh: undefined,
  906 + px: undefined,
  907 + pxmc: undefined,
  908 + pxjg: undefined,
  909 + xfzs: undefined,
  910 + yxf: 0, // 已消费
  911 + zgm: 1, // 总购买
  912 + ly: '购买', // 来源
  913 + projectNumber: 1, // 消费数量
  914 + qt2: undefined, // 品项类型
  915 + lqHytkJksyjList: [], // 健康师业绩列表
  916 + lqHytkKjbsyjList: [], // 科技部老师业绩列表
  917 + }
  918 + this.dataForm.lqHytkMxList.push(item);
  919 + // 重新计算总金额和总手工费
  920 + this.calculateTotalAmount();
  921 + this.calculateTotalLaborCost();
  922 + },
  923 + handleDelLqXhPxmxEntityList(index) {
  924 + this.dataForm.lqHytkMxList.splice(index, 1);
  925 + // 重新计算总金额和总手工费
  926 + this.calculateTotalAmount();
  927 + this.calculateTotalLaborCost();
  928 + },
  929 + validatePxList() {
  930 + const pxList = this.dataForm.lqHytkMxList;
808 931  
809   - // 处理提交格式
810   - this.processFormData();
811   - console.log(this.dataForm)
812   - // return
813   -
814   - this.dataForm.fileUrl = JSON.stringify(this.dataForm.fileUrl);
815   - if (!this.dataForm.id) {
816   - request({
817   - url: `/api/Extend/LqHytkHytk`,
818   - method: 'post',
819   - data: this.dataForm,
820   - }).then((res) => {
821   - this.$message({
822   - message: res.msg,
823   - type: 'success',
824   - duration: 1000,
825   - onClose: () => {
826   - this.visible = false,
827   - this.$emit('refresh', true)
828   - }
829   - })
830   - })
831   - } else {
832   - request({
833   - url: '/api/Extend/LqHytkHytk/' + this.dataForm.id,
834   - method: 'PUT',
835   - data: this.dataForm
836   - }).then((res) => {
837   - this.$message({
838   - message: res.msg,
839   - type: 'success',
840   - duration: 1000,
841   - onClose: () => {
842   - this.visible = false
843   - this.$emit('refresh', true)
844   - }
845   - })
846   - })
847   - }
848   - }
849   - })
850   - },
851   - // 品项相关方法
852   - addHandleLqXhPxmxEntityList() {
853   - let item = {
854   - id: undefined,
855   - glkdbh: undefined,
856   - px: undefined,
857   - pxmc: undefined,
858   - pxjg: undefined,
859   - xfzs: undefined,
860   - yxf: 0, // 已消费
861   - zgm: 1, // 总购买
862   - ly: '购买', // 来源
863   - projectNumber: 1, // 消费数量
864   - qt2: undefined, // 品项类型
865   - lqHytkJksyjList: [], // 健康师业绩列表
866   - lqHytkKjbsyjList: [], // 科技部老师业绩列表
  932 + // 1. 验证是否有品项
  933 + if (!pxList || pxList.length === 0) {
  934 + this.$message.error('请至少添加一个品项');
  935 + return false;
  936 + }
  937 +
  938 + // 2. 验证每个品项的信息
  939 + for (let i = 0; i < pxList.length; i++) {
  940 + const px = pxList[i];
  941 +
  942 + // 验证品项基本信息
  943 + if (!px.px || !px.pxmc) {
  944 + this.$message.error(`第${i + 1}个品项信息不完整,请重新选择`);
  945 + return false;
867 946 }
868   - this.dataForm.lqHytkMxList.push(item);
869   - // 重新计算总金额和总手工费
870   - this.calculateTotalAmount();
871   - this.calculateTotalLaborCost();
872   - },
873   - handleDelLqXhPxmxEntityList(index) {
874   - this.dataForm.lqHytkMxList.splice(index, 1);
875   - // 重新计算总金额和总手工费
876   - this.calculateTotalAmount();
877   - this.calculateTotalLaborCost();
878   - },
879   - validatePxList(){
880   - const pxList = this.dataForm.lqHytkMxList;
881   -
882   - // 1. 验证是否有品项
883   - if (!pxList || pxList.length === 0) {
884   - this.$message.error('请至少添加一个品项');
  947 + if (!px.pxjg || parseFloat(px.pxjg) <= 0) {
  948 + this.$message.error(`第${i + 1}个品项的价格必须大于0`);
885 949 return false;
886 950 }
887   -
888   - // 2. 验证每个品项的信息
889   - for (let i = 0; i < pxList.length; i++) {
890   - const px = pxList[i];
891   -
892   - // 验证品项基本信息
893   - if (!px.px || !px.pxmc) {
894   - this.$message.error(`第${i + 1}个品项信息不完整,请重新选择`);
  951 +
  952 + // 验证退卡次数不能超过剩余次数
  953 + if (px.RemainingCount && px.projectNumber > px.RemainingCount) {
  954 + this.$message.error(`第${i + 1}个品项的退卡次数(${px.projectNumber})不能超过剩余次数(${px.RemainingCount})`);
  955 + return false;
  956 + }
  957 +
  958 + // 验证健康师
  959 + if (!px.lqHytkJksyjList || px.lqHytkJksyjList.length === 0) {
  960 + this.$message.error(`第${i + 1}个品项必须至少选择一个健康师`);
  961 + return false;
  962 + }
  963 +
  964 + // 计算健康师业绩总和
  965 + let jksTotalYj = 0;
  966 + let jksTotalLaborCost = 0;
  967 + let jksTotalNumber = 0;
  968 +
  969 + for (let j = 0; j < px.lqHytkJksyjList.length; j++) {
  970 + const jks = px.lqHytkJksyjList[j];
  971 +
  972 + // 验证健康师是否选择
  973 + if (!jks.jks || !jks.jksxm) {
  974 + this.$message.error(`第${i + 1}个品项的第${j + 1}个健康师必须选择`);
895 975 return false;
896 976 }
897   - if (!px.pxjg || parseFloat(px.pxjg) <= 0) {
898   - this.$message.error(`第${i + 1}个品项的价格必须大于0`);
  977 +
  978 + // 验证健康师业绩必须填写
  979 + if (!jks.jksyj || jks.jksyj.trim() === "") {
  980 + this.$message.error(`第${i + 1}个品项的第${j + 1}个健康师业绩必须填写`);
899 981 return false;
900 982 }
901   -
902   - // 验证退卡次数不能超过剩余次数
903   - if (px.RemainingCount && px.projectNumber > px.RemainingCount) {
904   - this.$message.error(`第${i + 1}个品项的退卡次数(${px.projectNumber})不能超过剩余次数(${px.RemainingCount})`);
  983 +
  984 + // 验证业绩为数字
  985 + const yj = parseFloat(jks.jksyj);
  986 + if (isNaN(yj) || yj < 0) {
  987 + this.$message.error(`第${i + 1}个品项的第${j + 1}个健康师业绩必须为有效数字`);
905 988 return false;
906 989 }
907   -
908   - // 验证健康师
909   - if (!px.lqHytkJksyjList || px.lqHytkJksyjList.length === 0) {
910   - this.$message.error(`第${i + 1}个品项必须至少选择一个健康师`);
  990 +
  991 + jksTotalYj += yj;
  992 + jksTotalLaborCost += parseFloat(jks.laborCost) || 0;
  993 + jksTotalNumber += parseInt(jks.kdpxNumber) || 0;
  994 + }
  995 +
  996 + // 验证健康师业绩总和等于品项金额
  997 + const pxTotalAmount = px.pxjg * px.projectNumber;
  998 + if (Math.abs(jksTotalYj - pxTotalAmount) > 0.01) {
  999 + this.$message.error(`第${i + 1}个品项的健康师业绩总和(${jksTotalYj.toFixed(2)})必须等于品项金额(${pxTotalAmount.toFixed(2)})`);
  1000 + return false;
  1001 + }
  1002 +
  1003 + // 验证健康师手工费总和等于品项手工费
  1004 + const pxTotalLaborCost = (px.sgf || 0) * px.projectNumber;
  1005 + if (Math.abs(jksTotalLaborCost - pxTotalLaborCost) > 0.01) {
  1006 + this.$message.error(`第${i + 1}个品项的健康师手工费总和(${jksTotalLaborCost.toFixed(2)})必须等于品项手工费(${pxTotalLaborCost.toFixed(2)})`);
  1007 + return false;
  1008 + }
  1009 +
  1010 + // 验证健康师次数总和等于品项次数
  1011 + if (jksTotalNumber !== px.projectNumber) {
  1012 + this.$message.error(`第${i + 1}个品项的健康师次数总和(${jksTotalNumber})必须等于品项次数(${px.projectNumber})`);
  1013 + return false;
  1014 + }
  1015 +
  1016 + // 如果是科美品项,验证科技部老师
  1017 + if (px.qt2 === '科美') {
  1018 + if (!px.lqHytkKjbsyjList || px.lqHytkKjbsyjList.length === 0) {
  1019 + this.$message.error(`第${i + 1}个品项是科美品项,必须至少选择一个科技部老师`);
911 1020 return false;
912 1021 }
913   -
914   - // 计算健康师业绩总和
915   - let jksTotalYj = 0;
916   - let jksTotalLaborCost = 0;
917   - let jksTotalNumber = 0;
918   -
919   - for (let j = 0; j < px.lqHytkJksyjList.length; j++) {
920   - const jks = px.lqHytkJksyjList[j];
921   -
922   - // 验证健康师是否选择
923   - if (!jks.jks || !jks.jksxm) {
924   - this.$message.error(`第${i + 1}个品项的第${j + 1}个健康师必须选择`);
  1022 +
  1023 + // 计算科技部老师业绩总和
  1024 + let kjbTotalYj = 0;
  1025 + let kjbTotalLaborCost = 0;
  1026 + let kjbTotalNumber = 0;
  1027 +
  1028 + for (let k = 0; k < px.lqHytkKjbsyjList.length; k++) {
  1029 + const kjb = px.lqHytkKjbsyjList[k];
  1030 +
  1031 + // 验证科技部老师是否选择
  1032 + if (!kjb.kjbls || !kjb.kjblsxm) {
  1033 + this.$message.error(`第${i + 1}个品项的第${k + 1}个科技部老师必须选择`);
925 1034 return false;
926 1035 }
927   -
928   - // 验证健康师业绩必须填写
929   - if (!jks.jksyj || jks.jksyj.trim() === "") {
930   - this.$message.error(`第${i + 1}个品项的第${j + 1}个健康师业绩必须填写`);
  1036 +
  1037 + // 验证科技部老师业绩必须填写
  1038 + if (!kjb.kjblsyj || kjb.kjblsyj.trim() === "") {
  1039 + this.$message.error(`第${i + 1}个品项的第${k + 1}个科技部老师业绩必须填写`);
931 1040 return false;
932 1041 }
933   -
  1042 +
934 1043 // 验证业绩为数字
935   - const yj = parseFloat(jks.jksyj);
  1044 + const yj = parseFloat(kjb.kjblsyj);
936 1045 if (isNaN(yj) || yj < 0) {
937   - this.$message.error(`第${i + 1}个品项的第${j + 1}个健康师业绩必须为有效数字`);
  1046 + this.$message.error(`第${i + 1}个品项的第${k + 1}个科技部老师业绩必须为有效数字`);
938 1047 return false;
939 1048 }
940   -
941   - jksTotalYj += yj;
942   - jksTotalLaborCost += parseFloat(jks.laborCost) || 0;
943   - jksTotalNumber += parseInt(jks.kdpxNumber) || 0;
  1049 +
  1050 + kjbTotalYj += yj;
  1051 + kjbTotalLaborCost += parseFloat(kjb.laborCost) || 0;
  1052 + kjbTotalNumber += parseInt(kjb.hdpxNumber) || 0;
944 1053 }
945   -
946   - // 验证健康师业绩总和等于品项金额
947   - const pxTotalAmount = px.pxjg * px.projectNumber;
948   - if (Math.abs(jksTotalYj - pxTotalAmount) > 0.01) {
949   - this.$message.error(`第${i + 1}个品项的健康师业绩总和(${jksTotalYj.toFixed(2)})必须等于品项金额(${pxTotalAmount.toFixed(2)})`);
  1054 +
  1055 + // 验证科技部老师业绩总和等于品项金额
  1056 + if (Math.abs(kjbTotalYj - pxTotalAmount) > 0.01) {
  1057 + this.$message.error(`第${i + 1}个品项的科技部老师业绩总和(${kjbTotalYj.toFixed(2)})必须等于品项金额(${pxTotalAmount.toFixed(2)})`);
950 1058 return false;
951 1059 }
952   -
953   - // 验证健康师手工费总和等于品项手工费
954   - const pxTotalLaborCost = (px.sgf || 0) * px.projectNumber;
955   - if (Math.abs(jksTotalLaborCost - pxTotalLaborCost) > 0.01) {
956   - this.$message.error(`第${i + 1}个品项的健康师手工费总和(${jksTotalLaborCost.toFixed(2)})必须等于品项手工费(${pxTotalLaborCost.toFixed(2)})`);
  1060 +
  1061 + // 验证科技部老师手工费总和等于品项手工费
  1062 + if (Math.abs(kjbTotalLaborCost - pxTotalLaborCost) > 0.01) {
  1063 + this.$message.error(`第${i + 1}个品项的科技部老师手工费总和(${kjbTotalLaborCost.toFixed(2)})必须等于品项手工费(${pxTotalLaborCost.toFixed(2)})`);
957 1064 return false;
958 1065 }
959   -
960   - // 验证健康师次数总和等于品项次数
961   - if (jksTotalNumber !== px.projectNumber) {
962   - this.$message.error(`第${i + 1}个品项的健康师次数总和(${jksTotalNumber})必须等于品项次数(${px.projectNumber})`);
  1066 +
  1067 + // 验证科技部老师次数总和等于品项次数
  1068 + if (kjbTotalNumber !== px.projectNumber) {
  1069 + this.$message.error(`第${i + 1}个品项的科技部老师次数总和(${kjbTotalNumber})必须等于品项次数(${px.projectNumber})`);
963 1070 return false;
964 1071 }
965   -
966   - // 如果是科美品项,验证科技部老师
967   - if (px.qt2 === '科美') {
968   - if (!px.lqHytkKjbsyjList || px.lqHytkKjbsyjList.length === 0) {
969   - this.$message.error(`第${i + 1}个品项是科美品项,必须至少选择一个科技部老师`);
970   - return false;
971   - }
972   -
973   - // 计算科技部老师业绩总和
974   - let kjbTotalYj = 0;
975   - let kjbTotalLaborCost = 0;
976   - let kjbTotalNumber = 0;
977   -
978   - for (let k = 0; k < px.lqHytkKjbsyjList.length; k++) {
979   - const kjb = px.lqHytkKjbsyjList[k];
980   -
981   - // 验证科技部老师是否选择
982   - if (!kjb.kjbls || !kjb.kjblsxm) {
983   - this.$message.error(`第${i + 1}个品项的第${k + 1}个科技部老师必须选择`);
984   - return false;
985   - }
986   -
987   - // 验证科技部老师业绩必须填写
988   - if (!kjb.kjblsyj || kjb.kjblsyj.trim() === "") {
989   - this.$message.error(`第${i + 1}个品项的第${k + 1}个科技部老师业绩必须填写`);
990   - return false;
991   - }
992   -
993   - // 验证业绩为数字
994   - const yj = parseFloat(kjb.kjblsyj);
995   - if (isNaN(yj) || yj < 0) {
996   - this.$message.error(`第${i + 1}个品项的第${k + 1}个科技部老师业绩必须为有效数字`);
997   - return false;
998   - }
999   -
1000   - kjbTotalYj += yj;
1001   - kjbTotalLaborCost += parseFloat(kjb.laborCost) || 0;
1002   - kjbTotalNumber += parseInt(kjb.hdpxNumber) || 0;
1003   - }
1004   -
1005   - // 验证科技部老师业绩总和等于品项金额
1006   - if (Math.abs(kjbTotalYj - pxTotalAmount) > 0.01) {
1007   - this.$message.error(`第${i + 1}个品项的科技部老师业绩总和(${kjbTotalYj.toFixed(2)})必须等于品项金额(${pxTotalAmount.toFixed(2)})`);
1008   - return false;
1009   - }
1010   -
1011   - // 验证科技部老师手工费总和等于品项手工费
1012   - if (Math.abs(kjbTotalLaborCost - pxTotalLaborCost) > 0.01) {
1013   - this.$message.error(`第${i + 1}个品项的科技部老师手工费总和(${kjbTotalLaborCost.toFixed(2)})必须等于品项手工费(${pxTotalLaborCost.toFixed(2)})`);
1014   - return false;
1015   - }
1016   -
1017   - // 验证科技部老师次数总和等于品项次数
1018   - if (kjbTotalNumber !== px.projectNumber) {
1019   - this.$message.error(`第${i + 1}个品项的科技部老师次数总和(${kjbTotalNumber})必须等于品项次数(${px.projectNumber})`);
1020   - return false;
1021   - }
1022   - }
1023   - }
1024   -
1025   - return true;
1026   - },
1027   - // 处理表单数据
1028   - processFormData() {
1029   - // 检查是否有科美品项
1030   - const hasKemei = this.dataForm.lqHytkMxList.some(px => px.qt2 === '科美');
1031   -
1032   - // 设置是否有科技部
1033   - this.dataForm.sfykjb = hasKemei ? "是" : "否";
1034   -
1035   - // 处理品项列表,转换为指定格式
1036   - this.dataForm.lqHytkMxList = this.dataForm.lqHytkMxList.map(px => {
1037   - // 计算退卡金额和总价
1038   - const tkje = parseFloat(px.pxjg) * parseInt(px.projectNumber) || 0;
1039   - const f_TotalPrice = tkje;
1040   -
1041   - // 处理健康师列表
1042   - const lqHytkJksyjList = (px.lqHytkJksyjList || []).map(jks => ({
1043   - jks: jks.jks || '',
1044   - jksxm: jks.jksxm || '',
1045   - jkszh: jks.jkszh || '',
1046   - jksyj: parseFloat(jks.jksyj) || 0,
1047   - f_jsjid: jks.jsjId || '',
1048   - f_tkpxid: px.px || '',
1049   - f_LaborCost: parseFloat(jks.laborCost) || 0,
1050   - f_tkpxNumber: parseInt(px.projectNumber) || 0
1051   - }));
1052   -
1053   - // 处理科技部老师列表
1054   - const lqHytkKjbsyjList = (px.lqHytkKjbsyjList || []).map(kjb => ({
1055   - kjbls: kjb.kjbls || '',
1056   - kjblsxm: kjb.kjblsxm || '',
1057   - kjblszh: kjb.kjblszh || '',
1058   - kjblsyj: parseFloat(kjb.kjblsyj) || 0,
1059   - f_tkpxid: px.px || '',
1060   - f_LaborCost: parseFloat(kjb.laborCost) || 0,
1061   - f_tkpxNumber: parseInt(px.projectNumber) || 0
1062   - }));
1063   -
1064   - return {
1065   - px: px.px || '',
1066   - pxmc: px.pxmc || '',
1067   - pxjg: parseFloat(px.pxjg) || 0,
1068   - tkje: tkje,
1069   - f_ProjectNumber: parseInt(px.projectNumber) || 0,
1070   - f_SourceType: px.qt2 || '',
1071   - f_TotalPrice: f_TotalPrice,
1072   - lqHytkJksyjList: lqHytkJksyjList,
1073   - lqHytkKjbsyjList: lqHytkKjbsyjList
1074   - };
1075   - });
1076   - },
1077   - // 品项健康师相关方法
1078   - addPxJks(pxIndex) {
1079   - if (!this.dataForm.lqHytkMxList[pxIndex].lqHytkJksyjList) {
1080   - this.$set(this.dataForm.lqHytkMxList[pxIndex], 'lqHytkJksyjList', []);
1081   - }
1082   - // 获取当前品项的手工费
1083   - const currentPx = this.dataForm.lqHytkMxList[pxIndex];
1084   - const pxLaborCost = currentPx.sgf || 0;
1085   - const defaultNumber = 1;
1086   - const laborCost = pxLaborCost * defaultNumber; // 品项手工费 × 次数
1087   -
1088   - let item = {
1089   - "jks": "",
1090   - "jksxm": "",
1091   - "jkszh": "",
1092   - "jksyj": "",
1093   - "jsjId": "",
1094   - "laborCost": laborCost, // 品项手工费 × 次数
1095   - "kdpxNumber": defaultNumber // 默认次数为1
1096 1072 }
1097   - this.dataForm.lqHytkMxList[pxIndex].lqHytkJksyjList.push(item);
1098   - console.log('添加健康师:', {
1099   - pxLaborCost,
1100   - defaultNumber,
1101   - laborCost,
1102   - formula: `${pxLaborCost} × ${defaultNumber} = ${laborCost}`
1103   - });
1104   - },
1105   - removePxJks(pxIndex, jksIndex) {
1106   - this.dataForm.lqHytkMxList[pxIndex].lqHytkJksyjList.splice(jksIndex, 1);
1107   - },
1108   - // 品项科技部老师相关方法
1109   - addPxKjb(pxIndex) {
1110   - if (!this.dataForm.lqHytkMxList[pxIndex].lqHytkKjbsyjList) {
1111   - this.$set(this.dataForm.lqHytkMxList[pxIndex], 'lqHytkKjbsyjList', []);
1112   - }
1113   - // 获取当前品项的手工费
1114   - const currentPx = this.dataForm.lqHytkMxList[pxIndex];
1115   - const pxLaborCost = currentPx.sgf || 0;
1116   - const defaultNumber = 1;
1117   - const laborCost = pxLaborCost * defaultNumber; // 品项手工费 × 次数
1118   -
1119   - let item = {
1120   - "kjbls": "",
1121   - "kjblsyj": "",
1122   - "kjblsxm": "",
1123   - "kjblszh": "",
1124   - "laborCost": laborCost, // 品项手工费 × 次数
1125   - "hdpxNumber": defaultNumber // 默认次数为1
1126   - }
1127   - this.dataForm.lqHytkMxList[pxIndex].lqHytkKjbsyjList.push(item);
1128   - console.log('添加科技部老师:', {
1129   - pxLaborCost,
1130   - defaultNumber,
1131   - laborCost,
1132   - formula: `${pxLaborCost} × ${defaultNumber} = ${laborCost}`
1133   - });
1134   - },
1135   - removePxKjb(pxIndex, kjbIndex) {
1136   - this.dataForm.lqHytkMxList[pxIndex].lqHytkKjbsyjList.splice(kjbIndex, 1);
1137   - },
1138   - // 加载门店数据并设置默认门店
1139   - loadStoreDataAndSetDefault() {
1140   - console.log('开始加载门店数据和用户信息...');
1141   - // 先加载门店数据
1142   - this.loadStoreDataPromise().then(() => {
1143   - // 门店数据加载完成后,获取用户信息
1144   - return this.getCurrentUserStorePromise();
1145   - }).then((userData) => {
1146   - if (userData && userData.mdid) {
1147   - const userStoreId = userData.mdid;
1148   - console.log('用户门店ID:', userStoreId);
1149   - console.log('门店选项列表:', this.mdOptions);
1150   -
1151   - // 检查用户门店ID是否在门店列表中
1152   - const matchingStore = this.mdOptions.find(store => store.id === userStoreId);
1153   - if (matchingStore) {
1154   - this.dataForm.md = userStoreId;
1155   - this.dataForm.mdmc = matchingStore.fullName;
1156   - this.dataForm.mdbh = matchingStore.id;
1157   - console.log('找到匹配的门店,设置默认门店ID:', userStoreId);
1158   - console.log('匹配的门店信息:', matchingStore);
1159   - } else {
1160   - console.warn('用户门店ID在门店列表中未找到匹配项');
1161   - console.log('用户门店ID:', userStoreId);
1162   - console.log('可用门店ID列表:', this.mdOptions.map(s => s.id));
1163   - }
1164   - } else {
1165   - console.warn('用户数据中没有门店ID,无法设置默认值');
1166   - }
1167   -
1168   - // 加载健康师和科技部老师选项
1169   - this.getjksOptions();
1170   - this.getkjbOptions();
1171   - }).catch(err => {
1172   - console.error('加载数据失败:', err);
1173   - });
1174   - },
1175   - // 加载门店数据
1176   - loadStoreDataPromise() {
1177   - // 使用原来的数据接口方式
1178   - return previewDataInterface('730960205902251269').then(res => {
1179   - console.log('门店API原始响应:', res);
1180   - if (res.data && res.data.length > 0) {
1181   - this.mdOptions = res.data;
1182   - console.log('门店数据加载成功:', this.mdOptions);
1183   - return res.data;
  1073 + }
  1074 +
  1075 + return true;
  1076 + },
  1077 + // 处理表单数据
  1078 + processFormData() {
  1079 + // 检查是否有科美品项
  1080 + const hasKemei = this.dataForm.lqHytkMxList.some(px => px.qt2 === '科美');
  1081 +
  1082 + // 设置是否有科技部
  1083 + this.dataForm.sfykjb = hasKemei ? "是" : "否";
  1084 +
  1085 + // 处理品项列表,转换为指定格式
  1086 + this.dataForm.lqHytkMxList = this.dataForm.lqHytkMxList.map(px => {
  1087 + // 计算退卡金额和总价
  1088 + const tkje = parseFloat(px.pxjg) * parseInt(px.projectNumber) || 0;
  1089 + const f_TotalPrice = tkje;
  1090 +
  1091 + // 处理健康师列表
  1092 + const lqHytkJksyjList = (px.lqHytkJksyjList || []).map(jks => ({
  1093 + jks: jks.jks || '',
  1094 + jksxm: jks.jksxm || '',
  1095 + jkszh: jks.jkszh || '',
  1096 + jksyj: parseFloat(jks.jksyj) || 0,
  1097 + f_jsjid: jks.jsjId || '',
  1098 + f_tkpxid: px.px || '',
  1099 + f_LaborCost: parseFloat(jks.laborCost) || 0,
  1100 + f_tkpxNumber: parseInt(px.projectNumber) || 0
  1101 + }));
  1102 +
  1103 + // 处理科技部老师列表
  1104 + const lqHytkKjbsyjList = (px.lqHytkKjbsyjList || []).map(kjb => ({
  1105 + kjbls: kjb.kjbls || '',
  1106 + kjblsxm: kjb.kjblsxm || '',
  1107 + kjblszh: kjb.kjblszh || '',
  1108 + kjblsyj: parseFloat(kjb.kjblsyj) || 0,
  1109 + f_tkpxid: px.px || '',
  1110 + f_LaborCost: parseFloat(kjb.laborCost) || 0,
  1111 + f_tkpxNumber: parseInt(px.projectNumber) || 0
  1112 + }));
  1113 +
  1114 + return {
  1115 + px: px.px || '',
  1116 + pxmc: px.pxmc || '',
  1117 + pxjg: parseFloat(px.pxjg) || 0,
  1118 + tkje: tkje,
  1119 + f_ProjectNumber: parseInt(px.projectNumber) || 0,
  1120 + f_SourceType: px.qt2 || '',
  1121 + f_TotalPrice: f_TotalPrice,
  1122 + lqHytkJksyjList: lqHytkJksyjList,
  1123 + lqHytkKjbsyjList: lqHytkKjbsyjList
  1124 + };
  1125 + });
  1126 + },
  1127 + // 品项健康师相关方法
  1128 + addPxJks(pxIndex) {
  1129 + if (!this.dataForm.lqHytkMxList[pxIndex].lqHytkJksyjList) {
  1130 + this.$set(this.dataForm.lqHytkMxList[pxIndex], 'lqHytkJksyjList', []);
  1131 + }
  1132 + // 获取当前品项的手工费
  1133 + const currentPx = this.dataForm.lqHytkMxList[pxIndex];
  1134 + const pxLaborCost = currentPx.sgf || 0;
  1135 + const defaultNumber = 1;
  1136 + const laborCost = pxLaborCost * defaultNumber; // 品项手工费 × 次数
  1137 +
  1138 + let item = {
  1139 + "jks": "",
  1140 + "jksxm": "",
  1141 + "jkszh": "",
  1142 + "jksyj": "",
  1143 + "jsjId": "",
  1144 + "laborCost": laborCost, // 品项手工费 × 次数
  1145 + "kdpxNumber": defaultNumber // 默认次数为1
  1146 + }
  1147 + this.dataForm.lqHytkMxList[pxIndex].lqHytkJksyjList.push(item);
  1148 + console.log('添加健康师:', {
  1149 + pxLaborCost,
  1150 + defaultNumber,
  1151 + laborCost,
  1152 + formula: `${pxLaborCost} × ${defaultNumber} = ${laborCost}`
  1153 + });
  1154 + },
  1155 + removePxJks(pxIndex, jksIndex) {
  1156 + this.dataForm.lqHytkMxList[pxIndex].lqHytkJksyjList.splice(jksIndex, 1);
  1157 + },
  1158 + // 品项科技部老师相关方法
  1159 + addPxKjb(pxIndex) {
  1160 + if (!this.dataForm.lqHytkMxList[pxIndex].lqHytkKjbsyjList) {
  1161 + this.$set(this.dataForm.lqHytkMxList[pxIndex], 'lqHytkKjbsyjList', []);
  1162 + }
  1163 + // 获取当前品项的手工费
  1164 + const currentPx = this.dataForm.lqHytkMxList[pxIndex];
  1165 + const pxLaborCost = currentPx.sgf || 0;
  1166 + const defaultNumber = 1;
  1167 + const laborCost = pxLaborCost * defaultNumber; // 品项手工费 × 次数
  1168 +
  1169 + let item = {
  1170 + "kjbls": "",
  1171 + "kjblsyj": "",
  1172 + "kjblsxm": "",
  1173 + "kjblszh": "",
  1174 + "laborCost": laborCost, // 品项手工费 × 次数
  1175 + "hdpxNumber": defaultNumber // 默认次数为1
  1176 + }
  1177 + this.dataForm.lqHytkMxList[pxIndex].lqHytkKjbsyjList.push(item);
  1178 + console.log('添加科技部老师:', {
  1179 + pxLaborCost,
  1180 + defaultNumber,
  1181 + laborCost,
  1182 + formula: `${pxLaborCost} × ${defaultNumber} = ${laborCost}`
  1183 + });
  1184 + },
  1185 + removePxKjb(pxIndex, kjbIndex) {
  1186 + this.dataForm.lqHytkMxList[pxIndex].lqHytkKjbsyjList.splice(kjbIndex, 1);
  1187 + },
  1188 + // 加载门店数据并设置默认门店
  1189 + loadStoreDataAndSetDefault() {
  1190 + console.log('开始加载门店数据和用户信息...');
  1191 + // 先加载门店数据
  1192 + this.loadStoreDataPromise().then(() => {
  1193 + // 门店数据加载完成后,获取用户信息
  1194 + return this.getCurrentUserStorePromise();
  1195 + }).then((userData) => {
  1196 + if (userData && userData.mdid) {
  1197 + const userStoreId = userData.mdid;
  1198 + console.log('用户门店ID:', userStoreId);
  1199 + console.log('门店选项列表:', this.mdOptions);
  1200 +
  1201 + // 检查用户门店ID是否在门店列表中
  1202 + const matchingStore = this.mdOptions.find(store => store.id === userStoreId);
  1203 + if (matchingStore) {
  1204 + this.dataForm.md = userStoreId;
  1205 + this.dataForm.mdmc = matchingStore.fullName;
  1206 + this.dataForm.mdbh = matchingStore.id;
  1207 + console.log('找到匹配的门店,设置默认门店ID:', userStoreId);
  1208 + console.log('匹配的门店信息:', matchingStore);
1184 1209 } else {
1185   - console.warn('门店数据为空');
1186   - return [];
  1210 + console.warn('用户门店ID在门店列表中未找到匹配项');
  1211 + console.log('用户门店ID:', userStoreId);
  1212 + console.log('可用门店ID列表:', this.mdOptions.map(s => s.id));
1187 1213 }
1188   - }).catch(err => {
1189   - console.error('门店数据加载失败:', err);
  1214 + } else {
  1215 + console.warn('用户数据中没有门店ID,无法设置默认值');
  1216 + }
  1217 +
  1218 + // 加载健康师和科技部老师选项
  1219 + this.getjksOptions();
  1220 + this.getkjbOptions();
  1221 + }).catch(err => {
  1222 + console.error('加载数据失败:', err);
  1223 + });
  1224 + },
  1225 + // 加载门店数据
  1226 + loadStoreDataPromise() {
  1227 + // 使用原来的数据接口方式
  1228 + return previewDataInterface('730960205902251269').then(res => {
  1229 + console.log('门店API原始响应:', res);
  1230 + if (res.data && res.data.length > 0) {
  1231 + this.mdOptions = res.data;
  1232 + console.log('门店数据加载成功:', this.mdOptions);
  1233 + return res.data;
  1234 + } else {
  1235 + console.warn('门店数据为空');
1190 1236 return [];
  1237 + }
  1238 + }).catch(err => {
  1239 + console.error('门店数据加载失败:', err);
  1240 + return [];
  1241 + });
  1242 + },
  1243 + // 获取当前用户门店信息
  1244 + getCurrentUserStorePromise() {
  1245 + return new Promise((resolve, reject) => {
  1246 + getInfo().then(res => {
  1247 + resolve(res.data.userInfo);
  1248 + }).catch(err => {
  1249 + console.error('获取当前用户信息失败:', err);
  1250 + reject(err);
1191 1251 });
1192   - },
1193   - // 获取当前用户门店信息
1194   - getCurrentUserStorePromise() {
1195   - return new Promise((resolve, reject) => {
1196   - getInfo().then(res => {
1197   - resolve(res.data.userInfo);
1198   - }).catch(err => {
1199   - console.error('获取当前用户信息失败:', err);
1200   - reject(err);
1201   - });
1202   - });
1203   - },
1204   - }
  1252 + });
  1253 + },
1205 1254 }
  1255 +}
1206 1256 </script>
1207 1257  
1208 1258 <style scoped>
... ... @@ -1577,18 +1627,18 @@
1577 1627 width: 100%;
1578 1628 min-width: auto;
1579 1629 }
1580   -
  1630 +
1581 1631 .remaining-item-row {
1582 1632 flex-wrap: wrap;
1583 1633 gap: 8px;
1584 1634 }
1585   -
  1635 +
1586 1636 .item-name {
1587 1637 width: 100%;
1588 1638 margin-right: 0;
1589 1639 margin-bottom: 4px;
1590 1640 }
1591   -
  1641 +
1592 1642 .item-price,
1593 1643 .item-quantity,
1594 1644 .item-source {
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_jksyj/LqHytkJksyjEntity.cs
... ... @@ -137,5 +137,11 @@ namespace NCC.Extend.Entitys.lq_hytk_jksyj
137 137 /// </summary>
138 138 [SugarColumn(ColumnName = "F_ItemName")]
139 139 public string ItemName { get; set; }
  140 +
  141 + /// <summary>
  142 + /// 业绩类型
  143 + /// </summary>
  144 + [SugarColumn(ColumnName = "F_PerformanceType")]
  145 + public string PerformanceType { get; set; }
140 146 }
141 147 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_kjbsyj/LqHytkKjbsyjEntity.cs
... ... @@ -132,5 +132,11 @@ namespace NCC.Extend.Entitys.lq_hytk_kjbsyj
132 132 /// </summary>
133 133 [SugarColumn(ColumnName = "F_ItemName")]
134 134 public string ItemName { get; set; }
  135 +
  136 + /// <summary>
  137 + /// 业绩类型
  138 + /// </summary>
  139 + [SugarColumn(ColumnName = "F_PerformanceType")]
  140 + public string PerformanceType { get; set; }
135 141 }
136 142 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_hytk_mx/LqHytkMxEntity.cs
... ... @@ -120,5 +120,11 @@ namespace NCC.Extend.Entitys.lq_hytk_mx
120 120 /// </summary>
121 121 [SugarColumn(ColumnName = "F_IsEffective")]
122 122 public int IsEffective { get; set; } = StatusEnum.有效.GetHashCode();
  123 +
  124 + /// <summary>
  125 + /// 业绩类型
  126 + /// </summary>
  127 + [SugarColumn(ColumnName = "F_PerformanceType")]
  128 + public string PerformanceType { get; set; }
123 129 }
124 130 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_jksyj/LqKdJksyjEntity.cs
... ... @@ -100,5 +100,11 @@ namespace NCC.Extend.Entitys.lq_kd_jksyj
100 100 /// </summary>
101 101 [SugarColumn(ColumnName = "F_ItemName")]
102 102 public string ItemName { get; set; }
  103 +
  104 + /// <summary>
  105 + /// 业绩类型
  106 + /// </summary>
  107 + [SugarColumn(ColumnName = "F_PerformanceType")]
  108 + public string PerformanceType { get; set; }
103 109 }
104 110 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_kjbsyj/LqKdKjbsyjEntity.cs
... ... @@ -100,5 +100,11 @@ namespace NCC.Extend.Entitys.lq_kd_kjbsyj
100 100 /// </summary>
101 101 [SugarColumn(ColumnName = "F_ItemName")]
102 102 public string ItemName { get; set; }
  103 +
  104 + /// <summary>
  105 + /// 业绩类型
  106 + /// </summary>
  107 + [SugarColumn(ColumnName = "F_PerformanceType")]
  108 + public string PerformanceType { get; set; }
103 109 }
104 110 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_kd_pxmx/LqKdPxmxEntity.cs
... ... @@ -113,5 +113,11 @@ namespace NCC.Extend.Entitys.lq_kd_pxmx
113 113 /// </summary>
114 114 [SugarColumn(ColumnName = "F_ActivityId")]
115 115 public string ActivityId { get; set; }
  116 +
  117 + /// <summary>
  118 + /// 业绩类型
  119 + /// </summary>
  120 + [SugarColumn(ColumnName = "F_PerformanceType")]
  121 + public string PerformanceType { get; set; }
116 122 }
117 123 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_jksyj/LqXhJksyjEntity.cs
... ... @@ -148,5 +148,11 @@ namespace NCC.Extend.Entitys.lq_xh_jksyj
148 148 /// </summary>
149 149 [SugarColumn(ColumnName = "F_ItemName")]
150 150 public string ItemName { get; set; }
  151 +
  152 + /// <summary>
  153 + /// 业绩类型
  154 + /// </summary>
  155 + [SugarColumn(ColumnName = "F_PerformanceType")]
  156 + public string PerformanceType { get; set; }
151 157 }
152 158 }
153 159 \ No newline at end of file
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_kjbsyj/LqXhKjbsyjEntity.cs
... ... @@ -130,5 +130,11 @@ namespace NCC.Extend.Entitys.lq_xh_kjbsyj
130 130 /// </summary>
131 131 [SugarColumn(ColumnName = "F_ItemName")]
132 132 public string ItemName { get; set; }
  133 +
  134 + /// <summary>
  135 + /// 业绩类型
  136 + /// </summary>
  137 + [SugarColumn(ColumnName = "F_PerformanceType")]
  138 + public string PerformanceType { get; set; }
133 139 }
134 140 }
135 141 \ No newline at end of file
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_xh_pxmx/LqXhPxmxEntity.cs
... ... @@ -106,5 +106,11 @@ namespace NCC.Extend.Entitys.lq_xh_pxmx
106 106 /// </summary>
107 107 [SugarColumn(ColumnName = "F_IsEffective")]
108 108 public int? IsEffective { get; set; } = 1;
  109 +
  110 + /// <summary>
  111 + /// 业绩类型
  112 + /// </summary>
  113 + [SugarColumn(ColumnName = "F_PerformanceType")]
  114 + public string PerformanceType { get; set; }
109 115 }
110 116 }
... ...
netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/lq_yjmxb/LqYjmxbEntity.cs
... ... @@ -112,6 +112,12 @@ namespace NCC.Extend.Entitys.lq_yjmxb
112 112 /// </summary>
113 113 [SugarColumn(ColumnName = "zyj")]
114 114 public string Zyj { get; set; }
  115 +
  116 + /// <summary>
  117 + /// 业绩类型
  118 + /// </summary>
  119 + [SugarColumn(ColumnName = "F_PerformanceType")]
  120 + public string PerformanceType { get; set; }
115 121  
116 122 }
117 123 }
118 124 \ No newline at end of file
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqAttendanceSummaryService.cs
... ... @@ -374,6 +374,169 @@ namespace NCC.Extend
374 374 }
375 375 #endregion
376 376  
  377 + #region 生成健康师考勤模拟数据
  378 + /// <summary>
  379 + /// 生成健康师考勤模拟数据
  380 + /// </summary>
  381 + /// <remarks>
  382 + /// 为所有健康师生成指定年月的考勤模拟数据
  383 + ///
  384 + /// 规则:
  385 + /// - 80%以上的健康师出勤天数 >= 21天
  386 + /// - 其他健康师出勤天数随机生成(0-20天)
  387 + /// - 员工状态默认为1(在职)
  388 + ///
  389 + /// 示例请求:
  390 + /// ```json
  391 + /// {
  392 + /// "year": 2025,
  393 + /// "month": 11
  394 + /// }
  395 + /// ```
  396 + /// </remarks>
  397 + /// <param name="year">年份</param>
  398 + /// <param name="month">月份</param>
  399 + /// <returns>生成结果</returns>
  400 + /// <response code="200">成功生成考勤模拟数据</response>
  401 + /// <response code="400">参数错误</response>
  402 + /// <response code="500">生成失败</response>
  403 + [HttpPost("GenerateMockData/{year}/{month}")]
  404 + public async Task<dynamic> GenerateMockData(int year, int month)
  405 + {
  406 + try
  407 + {
  408 + // 验证参数
  409 + if (year < 2000 || year > 3000)
  410 + {
  411 + throw NCCException.Oh("年份参数无效");
  412 + }
  413 + if (month < 1 || month > 12)
  414 + {
  415 + throw NCCException.Oh("月份参数无效,应在1-12之间");
  416 + }
  417 +
  418 + // 查询所有健康师
  419 + var healthCoaches = await _db.Queryable<UserEntity>()
  420 + .Where(u => u.Gw == "健康师" && u.EnabledMark == 1 && (u.DeleteMark == null || u.DeleteMark == 0))
  421 + .Select(u => new { u.Id, u.RealName })
  422 + .ToListAsync();
  423 +
  424 + if (!healthCoaches.Any())
  425 + {
  426 + throw NCCException.Oh("未找到健康师用户");
  427 + }
  428 +
  429 + // 检查是否已存在该年月的考勤数据
  430 + var existingRecords = await _db.Queryable<LqAttendanceSummaryEntity>()
  431 + .Where(a => a.Year == year && a.Month == month)
  432 + .CountAsync();
  433 +
  434 + if (existingRecords > 0)
  435 + {
  436 + throw NCCException.Oh($"已存在{year}年{month}月的考勤数据,请先清空后再生成");
  437 + }
  438 +
  439 + var totalCount = healthCoaches.Count;
  440 + var highAttendanceCount = (int)Math.Ceiling(totalCount * 0.8); // 80%以上,向上取整
  441 + var lowAttendanceCount = totalCount - highAttendanceCount;
  442 +
  443 + var random = new Random();
  444 + var entitiesToInsert = new List<LqAttendanceSummaryEntity>();
  445 + var now = DateTime.Now;
  446 +
  447 + // 生成考勤数据
  448 + for (int i = 0; i < totalCount; i++)
  449 + {
  450 + var healthCoach = healthCoaches[i];
  451 + decimal workDays;
  452 + decimal leaveDays;
  453 + decimal restDays;
  454 +
  455 + if (i < highAttendanceCount)
  456 + {
  457 + // 80%以上的健康师:出勤天数 >= 21天
  458 + workDays = random.Next(21, 31); // 21-30天
  459 + var remainingDays = 30 - workDays;
  460 + // 剩余天数分配给请假和休息
  461 + if (remainingDays > 0)
  462 + {
  463 + leaveDays = random.Next(0, (int)remainingDays + 1);
  464 + restDays = remainingDays - leaveDays;
  465 + }
  466 + else
  467 + {
  468 + leaveDays = 0;
  469 + restDays = 0;
  470 + }
  471 + }
  472 + else
  473 + {
  474 + // 其他20%的健康师:出勤天数 < 21天
  475 + workDays = random.Next(0, 21); // 0-20天
  476 + var remainingDays = 30 - workDays;
  477 + // 剩余天数分配给请假和休息
  478 + if (remainingDays > 0)
  479 + {
  480 + leaveDays = random.Next(0, (int)remainingDays + 1);
  481 + restDays = remainingDays - leaveDays;
  482 + }
  483 + else
  484 + {
  485 + leaveDays = 0;
  486 + restDays = 0;
  487 + }
  488 + }
  489 +
  490 + var entity = new LqAttendanceSummaryEntity
  491 + {
  492 + Id = YitIdHelper.NextId().ToString(),
  493 + UserId = healthCoach.Id,
  494 + Year = year,
  495 + Month = month,
  496 + EmployeeStatus = 1, // 在职
  497 + WorkDays = workDays,
  498 + LeaveDays = leaveDays,
  499 + RestDays = restDays,
  500 + Remark = "模拟数据",
  501 + CreateUser = _userManager.UserId ?? "system",
  502 + CreateTime = now,
  503 + UpdateUser = _userManager.UserId ?? "system",
  504 + UpdateTime = now,
  505 + IsEffective = 1
  506 + };
  507 + entitiesToInsert.Add(entity);
  508 + }
  509 +
  510 + // 批量插入
  511 + await _db.Insertable(entitiesToInsert).ExecuteCommandAsync();
  512 +
  513 + // 统计结果
  514 + var highAttendanceActual = entitiesToInsert.Count(e => e.WorkDays >= 21);
  515 + var highAttendancePercentage = (decimal)highAttendanceActual / totalCount * 100;
  516 +
  517 + return new
  518 + {
  519 + success = true,
  520 + message = "生成考勤模拟数据成功",
  521 + data = new
  522 + {
  523 + year = year,
  524 + month = month,
  525 + totalCount = totalCount,
  526 + highAttendanceCount = highAttendanceActual,
  527 + highAttendancePercentage = Math.Round(highAttendancePercentage, 2),
  528 + generatedCount = entitiesToInsert.Count
  529 + }
  530 + };
  531 + }
  532 + catch (Exception ex)
  533 + {
  534 + _logger.LogError(ex, $"生成健康师考勤模拟数据失败 - 年份: {year}, 月份: {month}");
  535 + throw NCCException.Oh($"生成健康师考勤模拟数据失败:{ex.Message}");
  536 + }
  537 + }
  538 + #endregion
  539 +
377 540  
378 541 }
379 542 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs
... ... @@ -354,6 +354,7 @@ namespace NCC.Extend.LqHytkHytk
354 354 TotalPrice = item.F_TotalPrice ?? (item.pxjg * (item.F_ProjectNumber ?? 1)),
355 355 IsEffective = StatusEnum.有效.GetHashCode(),
356 356 ItemCategory = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
  357 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
357 358 };
358 359 allMxEntities.Add(lqHytkMxEntity);
359 360  
... ... @@ -382,7 +383,8 @@ namespace NCC.Extend.LqHytkHytk
382 383 ItemCategory = lqHytkMxEntity.ItemCategory,
383 384 ItemId = lqHytkMxEntity.Px,
384 385 StoreId = newEntity.Md,
385   - ItemName = lqHytkMxEntity.Pxmc
  386 + ItemName = lqHytkMxEntity.Pxmc,
  387 + PerformanceType = lqHytkMxEntity.PerformanceType
386 388 }
387 389 );
388 390 }
... ... @@ -413,7 +415,8 @@ namespace NCC.Extend.LqHytkHytk
413 415 ItemCategory = lqHytkMxEntity.ItemCategory,
414 416 ItemId = lqHytkMxEntity.Px,
415 417 StoreId = newEntity.Md,
416   - ItemName = lqHytkMxEntity.Pxmc
  418 + ItemName = lqHytkMxEntity.Pxmc,
  419 + PerformanceType = lqHytkMxEntity.PerformanceType
417 420 }
418 421 );
419 422 }
... ... @@ -513,6 +516,7 @@ namespace NCC.Extend.LqHytkHytk
513 516 SourceType = item.F_SourceType,
514 517 TotalPrice = item.F_TotalPrice ?? (item.pxjg * (item.F_ProjectNumber ?? 1)),
515 518 ItemCategory = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
  519 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
516 520 };
517 521 allMxEntities.Add(lqHytkMxEntity);
518 522  
... ... @@ -540,7 +544,8 @@ namespace NCC.Extend.LqHytkHytk
540 544 ItemCategory = lqHytkMxEntity.ItemCategory,
541 545 ItemId = lqHytkMxEntity.Px,
542 546 StoreId = entity.Md,
543   - ItemName = lqHytkMxEntity.Pxmc
  547 + ItemName = lqHytkMxEntity.Pxmc,
  548 + PerformanceType = lqHytkMxEntity.PerformanceType
544 549 }
545 550 );
546 551 }
... ... @@ -569,7 +574,8 @@ namespace NCC.Extend.LqHytkHytk
569 574 ItemCategory = lqHytkMxEntity.ItemCategory,
570 575 ItemId = lqHytkMxEntity.Px,
571 576 StoreId = entity.Md,
572   - ItemName = lqHytkMxEntity.Pxmc
  577 + ItemName = lqHytkMxEntity.Pxmc,
  578 + PerformanceType = lqHytkMxEntity.PerformanceType
573 579 }
574 580 );
575 581 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
... ... @@ -932,6 +932,7 @@ namespace NCC.Extend.LqKdKdjlb
932 932 IsEffective = StatusEnum.有效.GetHashCode(),
933 933 ActivityId = input.activityId,
934 934 ItemCategory = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
  935 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
935 936 };
936 937 allPxmxEntities.Add(lqKdPxmxEntity);
937 938 // 收集该品项关联的健康师业绩
... ... @@ -957,7 +958,8 @@ namespace NCC.Extend.LqKdKdjlb
957 958 ItemCategory = lqKdPxmxEntity.ItemCategory,
958 959 ItemId = lqKdPxmxEntity.Px,
959 960 ItemName = lqKdPxmxEntity.Pxmc,
960   - StoreId = entity.Djmd
  961 + StoreId = entity.Djmd,
  962 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
961 963 });
962 964 }
963 965 }
... ... @@ -982,7 +984,8 @@ namespace NCC.Extend.LqKdKdjlb
982 984 ItemCategory = lqKdPxmxEntity.ItemCategory,
983 985 ItemId = lqKdPxmxEntity.Px,
984 986 ItemName = lqKdPxmxEntity.Pxmc,
985   - StoreId = entity.Djmd
  987 + StoreId = entity.Djmd,
  988 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
986 989 }
987 990 );
988 991 }
... ... @@ -1272,6 +1275,7 @@ namespace NCC.Extend.LqKdKdjlb
1272 1275 IsEffective = StatusEnum.有效.GetHashCode(),
1273 1276 ActivityId = input.activityId,
1274 1277 ItemCategory = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
  1278 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
1275 1279 };
1276 1280 allPxmxEntities.Add(lqKdPxmxEntity);
1277 1281  
... ... @@ -1298,6 +1302,7 @@ namespace NCC.Extend.LqKdKdjlb
1298 1302 ItemId = lqKdPxmxEntity.Px,
1299 1303 StoreId = entity.Djmd,
1300 1304 ItemName = lqKdPxmxEntity.Pxmc,
  1305 + PerformanceType = lqKdPxmxEntity.PerformanceType,
1301 1306 });
1302 1307 }
1303 1308 }
... ... @@ -1323,6 +1328,7 @@ namespace NCC.Extend.LqKdKdjlb
1323 1328 ItemId = lqKdPxmxEntity.Px,
1324 1329 StoreId = entity.Djmd,
1325 1330 ItemName = lqKdPxmxEntity.Pxmc,
  1331 + PerformanceType = lqKdPxmxEntity.PerformanceType,
1326 1332 });
1327 1333 }
1328 1334 }
... ... @@ -2837,7 +2843,6 @@ namespace NCC.Extend.LqKdKdjlb
2837 2843 // 4. 创建退卡品项明细和业绩记录
2838 2844 var refundMxEntities = new List<LqHytkMxEntity>();
2839 2845 var refundJksyjEntities = new List<LqHytkJksyjEntity>();
2840   -
2841 2846 var refundKjbsyjEntities = new List<LqHytkKjbsyjEntity>();
2842 2847  
2843 2848 foreach (var item in input.TransferItems)
... ... @@ -2863,6 +2868,7 @@ namespace NCC.Extend.LqKdKdjlb
2863 2868 TotalPrice = totalItemDeduction,
2864 2869 IsEffective = StatusEnum.有效.GetHashCode(),
2865 2870 ItemCategory = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.Qt2).FirstAsync(),
  2871 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.Fl3).FirstAsync() ?? "",
2866 2872 };
2867 2873 refundMxEntities.Add(refundMxEntity);
2868 2874 var refundKdyjEntities = _db.Queryable<LqKdJksyjEntity>().Where(p => p.Kdpxid == item.BillingItemId).ToList();
... ... @@ -2885,7 +2891,7 @@ namespace NCC.Extend.LqKdKdjlb
2885 2891 Jks = jks.Jkszh,
2886 2892 Jksxm = jks.Jksxm,
2887 2893 Jkszh = jks.Jkszh,
2888   - Jksyj = (totalItemDeduction / refundKdyjEntities.Count()),
  2894 + Jksyj = totalItemDeduction / refundKdyjEntities.Count(),
2889 2895 Tksj = DateTime.Now,
2890 2896 F_jsjid = GetMonTeam.JsjId,
2891 2897 F_tkpxid = refundMxEntity.Id,
... ... @@ -2897,7 +2903,8 @@ namespace NCC.Extend.LqKdKdjlb
2897 2903 ItemCategory = refundMxEntity.ItemCategory,
2898 2904 ItemId = refundMxEntity.Px,
2899 2905 StoreId = refundEntity.Md,
2900   - ItemName = refundMxEntity.Pxmc
  2906 + ItemName = refundMxEntity.Pxmc,
  2907 + PerformanceType = refundMxEntity.PerformanceType
2901 2908 });
2902 2909 }
2903 2910 //查询科技部老师的业绩
... ... @@ -2924,7 +2931,8 @@ namespace NCC.Extend.LqKdKdjlb
2924 2931 ItemCategory = refundMxEntity.ItemCategory,
2925 2932 ItemId = refundMxEntity.Px,
2926 2933 StoreId = refundEntity.Md,
2927   - ItemName = refundMxEntity.Pxmc
  2934 + ItemName = refundMxEntity.Pxmc,
  2935 + PerformanceType = refundMxEntity.PerformanceType
2928 2936 });
2929 2937 }
2930 2938 }
... ... @@ -2967,6 +2975,29 @@ namespace NCC.Extend.LqKdKdjlb
2967 2975 foreach (var item in input.TransferItems)
2968 2976 {
2969 2977 var refundPxmxEntity = await _db.Queryable<LqKdPxmxEntity>().Where(p => p.Id == item.BillingItemId).FirstAsync();
  2978 + // 计算转卡金额和数量
  2979 + var transferAmount = item.ItemPrice * item.TransferQuantity;
  2980 + var transferQuantity = item.TransferQuantity;
  2981 +
  2982 + // 获取原开单品项的总金额和总数量
  2983 + var originalTotalPrice = refundPxmxEntity.TotalPrice > 0 ? refundPxmxEntity.TotalPrice : refundPxmxEntity.ActualPrice;
  2984 + var originalProjectNumber = refundPxmxEntity.ProjectNumber > 0 ? refundPxmxEntity.ProjectNumber : 1;
  2985 +
  2986 + // 计算转卡比例(优先使用金额比例,如果金额为0则使用数量比例)
  2987 + decimal transferRatio = 0;
  2988 + if (originalTotalPrice > 0)
  2989 + {
  2990 + transferRatio = transferAmount / originalTotalPrice;
  2991 + }
  2992 + else if (originalProjectNumber > 0)
  2993 + {
  2994 + transferRatio = (decimal)transferQuantity / originalProjectNumber;
  2995 + }
  2996 + else
  2997 + {
  2998 + transferRatio = 1; // 如果原数据异常,默认按100%计算
  2999 + }
  3000 +
2970 3001 var billingPxmxEntity = new LqKdPxmxEntity
2971 3002 {
2972 3003 Id = YitIdHelper.NextId().ToString(),
... ... @@ -2979,53 +3010,142 @@ namespace NCC.Extend.LqKdKdjlb
2979 3010 ProjectNumber = item.TransferQuantity,
2980 3011 IsEnabled = StatusEnum.有效.GetHashCode(),
2981 3012 SourceType = refundPxmxEntity.SourceType,
2982   - TotalPrice = item.ItemPrice * item.TransferQuantity,
2983   - ActualPrice = item.ItemPrice * item.TransferQuantity,
  3013 + TotalPrice = transferAmount,
  3014 + ActualPrice = transferAmount,
2984 3015 IsEffective = StatusEnum.有效.GetHashCode(),
2985 3016 Remark = $"从会员 {fromMember.Khmc} 转入",
2986 3017 ItemCategory = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.Qt2).FirstAsync(),
  3018 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == refundPxmxEntity.Px).Select(x => x.Fl3).FirstAsync() ?? "",
2987 3019 };
2988 3020 billingPxmxEntities.Add(billingPxmxEntity);
2989 3021  
2990   - foreach (var jks in refundJksyjEntities)
  3022 + // 查询原开单记录的健康师业绩
  3023 + var billingKdyjEntitiesList = _db.Queryable<LqKdJksyjEntity>().Where(p => p.Kdpxid == item.BillingItemId).ToList();
  3024 + if (billingKdyjEntitiesList.Any())
2991 3025 {
2992   - billingJksyjEntities.Add(new LqKdJksyjEntity
  3026 + // 计算原开单所有健康师的总业绩
  3027 + var originalTotalJksyj = billingKdyjEntitiesList.Sum(x => decimal.Parse(x.Jksyj ?? "0"));
  3028 + // 如果原开单总业绩为0,则按转卡金额均分
  3029 + if (originalTotalJksyj == 0)
2993 3030 {
2994   - Id = YitIdHelper.NextId().ToString(),
2995   - Glkdbh = billingId,
2996   - Jks = jks.Jkszh,
2997   - Jksxm = jks.Jksxm,
2998   - Jkszh = jks.Jkszh,
2999   - Jksyj = jks.Jksyj.ToString(),
3000   - Yjsj = transferTime,
3001   - Jsj_id = jks.F_jsjid,
3002   - Kdpxid = billingPxmxEntity.Id,
3003   - IsEffective = StatusEnum.有效.GetHashCode(),
3004   - ItemCategory = billingPxmxEntity.ItemCategory,
3005   - ItemId = billingPxmxEntity.Px,
3006   - StoreId = billingEntity.Djmd,
3007   - ItemName = billingPxmxEntity.Pxmc
3008   - });
  3031 + var avgJksyj = transferAmount / billingKdyjEntitiesList.Count;
  3032 + foreach (var jks in billingKdyjEntitiesList)
  3033 + {
  3034 + billingJksyjEntities.Add(new LqKdJksyjEntity
  3035 + {
  3036 + Id = YitIdHelper.NextId().ToString(),
  3037 + Glkdbh = billingId,
  3038 + Jks = jks.Jkszh,
  3039 + Jksxm = jks.Jksxm,
  3040 + Jkszh = jks.Jkszh,
  3041 + Jksyj = avgJksyj.ToString("F2"),
  3042 + Yjsj = transferTime,
  3043 + Jsj_id = jks.Jsj_id,
  3044 + Kdpxid = billingPxmxEntity.Id,
  3045 + IsEffective = StatusEnum.有效.GetHashCode(),
  3046 + ItemCategory = billingPxmxEntity.ItemCategory,
  3047 + ItemId = billingPxmxEntity.Px,
  3048 + StoreId = billingEntity.Djmd,
  3049 + ItemName = billingPxmxEntity.Pxmc,
  3050 + PerformanceType = billingPxmxEntity.PerformanceType
  3051 + });
  3052 + }
  3053 + }
  3054 + else
  3055 + {
  3056 + // 按原业绩比例计算转卡后的业绩
  3057 + foreach (var jks in billingKdyjEntitiesList)
  3058 + {
  3059 + var originalJksyj = decimal.Parse(jks.Jksyj ?? "0");
  3060 + // 计算该健康师在原开单中的业绩占比
  3061 + var jksRatio = originalTotalJksyj > 0 ? originalJksyj / originalTotalJksyj : 0;
  3062 + // 转卡后的业绩 = 转卡金额 × 该健康师的业绩占比
  3063 + var transferJksyj = transferAmount * jksRatio;
  3064 +
  3065 + billingJksyjEntities.Add(new LqKdJksyjEntity
  3066 + {
  3067 + Id = YitIdHelper.NextId().ToString(),
  3068 + Glkdbh = billingId,
  3069 + Jks = jks.Jkszh,
  3070 + Jksxm = jks.Jksxm,
  3071 + Jkszh = jks.Jkszh,
  3072 + Jksyj = transferJksyj.ToString("F2"),
  3073 + Yjsj = transferTime,
  3074 + Jsj_id = jks.Jsj_id,
  3075 + Kdpxid = billingPxmxEntity.Id,
  3076 + IsEffective = StatusEnum.有效.GetHashCode(),
  3077 + ItemCategory = billingPxmxEntity.ItemCategory,
  3078 + ItemId = billingPxmxEntity.Px,
  3079 + StoreId = billingEntity.Djmd,
  3080 + ItemName = billingPxmxEntity.Pxmc,
  3081 + PerformanceType = billingPxmxEntity.PerformanceType
  3082 + });
  3083 + }
  3084 + }
3009 3085 }
3010 3086  
3011   - foreach (var kjbs in refundKjbsyjEntities)
  3087 + // 查询原开单记录的科技部老师业绩
  3088 + var billingKjbsyjEntitiesList = _db.Queryable<LqKdKjbsyjEntity>().Where(p => p.Kdpxid == item.BillingItemId).ToList();
  3089 + if (billingKjbsyjEntitiesList.Any())
3012 3090 {
3013   - billingKjbsyjEntities.Add(new LqKdKjbsyjEntity
  3091 + // 计算原开单所有科技部老师的总业绩
  3092 + var originalTotalKjbsyj = billingKjbsyjEntitiesList.Sum(x => decimal.Parse(x.Kjblsyj ?? "0"));
  3093 +
  3094 + // 如果原开单总业绩为0,则按转卡金额均分
  3095 + if (originalTotalKjbsyj == 0)
3014 3096 {
3015   - Id = YitIdHelper.NextId().ToString(),
3016   - Glkdbh = billingId,
3017   - Kjbls = kjbs.Kjbls,
3018   - Kjblsxm = kjbs.Kjblsxm,
3019   - Kjblszh = kjbs.Kjblszh,
3020   - Kjblsyj = kjbs.Kjblsyj.ToString(),
3021   - Yjsj = transferTime,
3022   - Kdpxid = billingPxmxEntity.Id,
3023   - IsEffective = StatusEnum.有效.GetHashCode(),
3024   - ItemCategory = billingPxmxEntity.ItemCategory,
3025   - ItemId = billingPxmxEntity.Px,
3026   - StoreId = billingEntity.Djmd,
3027   - ItemName = billingPxmxEntity.Pxmc
3028   - });
  3097 + var avgKjbsyj = transferAmount / billingKjbsyjEntitiesList.Count;
  3098 + foreach (var kjbs in billingKjbsyjEntitiesList)
  3099 + {
  3100 + billingKjbsyjEntities.Add(new LqKdKjbsyjEntity
  3101 + {
  3102 + Id = YitIdHelper.NextId().ToString(),
  3103 + Glkdbh = billingId,
  3104 + Kjbls = kjbs.Kjbls,
  3105 + Kjblsxm = kjbs.Kjblsxm,
  3106 + Kjblszh = kjbs.Kjblszh,
  3107 + Kjblsyj = avgKjbsyj.ToString("F2"),
  3108 + Yjsj = transferTime,
  3109 + Kdpxid = billingPxmxEntity.Id,
  3110 + IsEffective = StatusEnum.有效.GetHashCode(),
  3111 + ItemCategory = billingPxmxEntity.ItemCategory,
  3112 + ItemId = billingPxmxEntity.Px,
  3113 + StoreId = billingEntity.Djmd,
  3114 + ItemName = billingPxmxEntity.Pxmc,
  3115 + PerformanceType = billingPxmxEntity.PerformanceType
  3116 + });
  3117 + }
  3118 + }
  3119 + else
  3120 + {
  3121 + // 按原业绩比例计算转卡后的业绩
  3122 + foreach (var kjbs in billingKjbsyjEntitiesList)
  3123 + {
  3124 + var originalKjbsyj = decimal.Parse(kjbs.Kjblsyj ?? "0");
  3125 + // 计算该科技部老师在原开单中的业绩占比
  3126 + var kjbsRatio = originalTotalKjbsyj > 0 ? originalKjbsyj / originalTotalKjbsyj : 0;
  3127 + // 转卡后的业绩 = 转卡金额 × 该科技部老师的业绩占比
  3128 + var transferKjbsyj = transferAmount * kjbsRatio;
  3129 +
  3130 + billingKjbsyjEntities.Add(new LqKdKjbsyjEntity
  3131 + {
  3132 + Id = YitIdHelper.NextId().ToString(),
  3133 + Glkdbh = billingId,
  3134 + Kjbls = kjbs.Kjbls,
  3135 + Kjblsxm = kjbs.Kjblsxm,
  3136 + Kjblszh = kjbs.Kjblszh,
  3137 + Kjblsyj = transferKjbsyj.ToString("F2"),
  3138 + Yjsj = transferTime,
  3139 + Kdpxid = billingPxmxEntity.Id,
  3140 + IsEffective = StatusEnum.有效.GetHashCode(),
  3141 + ItemCategory = billingPxmxEntity.ItemCategory,
  3142 + ItemId = billingPxmxEntity.Px,
  3143 + StoreId = billingEntity.Djmd,
  3144 + ItemName = billingPxmxEntity.Pxmc,
  3145 + PerformanceType = billingPxmxEntity.PerformanceType
  3146 + });
  3147 + }
  3148 + }
3029 3149 }
3030 3150 }
3031 3151 //记录转卡日志
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqXhHyhkService.cs
... ... @@ -938,6 +938,7 @@ namespace NCC.Extend.LqXhHyhk
938 938 SourceType = item.sourceType,
939 939 IsEffective = StatusEnum.有效.GetHashCode(),
940 940 ItemCategory = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
  941 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
941 942 };
942 943 allPxmxEntities.Add(lqXhPxmxEntity);
943 944  
... ... @@ -971,7 +972,8 @@ namespace NCC.Extend.LqXhHyhk
971 972 ItemCategory = lqXhPxmxEntity.ItemCategory,
972 973 ItemId = lqXhPxmxEntity.Px,
973 974 StoreId = entity.Md,
974   - ItemName = lqXhPxmxEntity.Pxmc
  975 + ItemName = lqXhPxmxEntity.Pxmc,
  976 + PerformanceType = lqXhPxmxEntity.PerformanceType
975 977 }
976 978 );
977 979 }
... ... @@ -1010,7 +1012,8 @@ namespace NCC.Extend.LqXhHyhk
1010 1012 ItemCategory = lqXhPxmxEntity.ItemCategory,
1011 1013 ItemId = lqXhPxmxEntity.Px,
1012 1014 StoreId = entity.Md,
1013   - ItemName = lqXhPxmxEntity.Pxmc
  1015 + ItemName = lqXhPxmxEntity.Pxmc,
  1016 + PerformanceType = lqXhPxmxEntity.PerformanceType
1014 1017 }
1015 1018 );
1016 1019 }
... ... @@ -1313,6 +1316,7 @@ namespace NCC.Extend.LqXhHyhk
1313 1316 OvertimeProjectNumber = (decimal)(entity.OvertimeCoefficient * (item.projectNumber ?? 0)),
1314 1317 ProjectNumber = (decimal)((item.projectNumber ?? 0) + (entity.OvertimeCoefficient * (item.projectNumber ?? 0))),
1315 1318 ItemCategory = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
  1319 + PerformanceType = await _db.Queryable<LqXmzlEntity>().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
1316 1320 };
1317 1321 allPxmxEntities.Add(lqXhPxmxEntity);
1318 1322  
... ... @@ -1346,7 +1350,8 @@ namespace NCC.Extend.LqXhHyhk
1346 1350 ItemCategory = lqXhPxmxEntity.ItemCategory,
1347 1351 ItemId = lqXhPxmxEntity.Px,
1348 1352 StoreId = entity.Md,
1349   - ItemName = lqXhPxmxEntity.Pxmc
  1353 + ItemName = lqXhPxmxEntity.Pxmc,
  1354 + PerformanceType = lqXhPxmxEntity.PerformanceType
1350 1355 }
1351 1356 );
1352 1357 }
... ... @@ -1384,7 +1389,8 @@ namespace NCC.Extend.LqXhHyhk
1384 1389 ItemCategory = lqXhPxmxEntity.ItemCategory,
1385 1390 ItemId = lqXhPxmxEntity.Px,
1386 1391 StoreId = entity.Md,
1387   - ItemName = lqXhPxmxEntity.Pxmc
  1392 + ItemName = lqXhPxmxEntity.Pxmc,
  1393 + PerformanceType = lqXhPxmxEntity.PerformanceType
1388 1394 });
1389 1395 }
1390 1396 }
... ...
sql/更新历史数据业绩类型字段.sql 0 → 100644
  1 +-- 更新历史数据的业绩类型字段
  2 +-- 业绩类型根据品项表(lq_xmzl)的 fl3 字段来设置
  3 +-- fl3 字段是"分类③-工资用",用于区分不同的业绩类型
  4 +
  5 +-- 1. 更新开单品项表(通过品项ID关联品项表的fl3字段)
  6 +UPDATE lq_kd_pxmx pxmx
  7 +INNER JOIN lq_xmzl xmzl ON pxmx.px = xmzl.F_Id
  8 +SET pxmx.F_PerformanceType = COALESCE(xmzl.fl3, '')
  9 +WHERE (pxmx.F_PerformanceType IS NULL OR pxmx.F_PerformanceType = '')
  10 + AND pxmx.F_IsEffective = 1;
  11 +
  12 +-- 2. 更新开单健康师业绩表(通过品项ID或开单品项明细ID关联品项表的fl3字段)
  13 +UPDATE lq_kd_jksyj jksyj
  14 +LEFT JOIN lq_kd_pxmx pxmx ON jksyj.F_kdpxid = pxmx.F_Id
  15 +LEFT JOIN lq_xmzl xmzl ON COALESCE(jksyj.F_ItemId, pxmx.px) = xmzl.F_Id
  16 +SET jksyj.F_PerformanceType = COALESCE(xmzl.fl3, '')
  17 +WHERE (jksyj.F_PerformanceType IS NULL OR jksyj.F_PerformanceType = '')
  18 + AND jksyj.F_IsEffective = 1
  19 + AND xmzl.F_Id IS NOT NULL;
  20 +
  21 +-- 3. 更新开单科技部老师业绩表(通过品项ID或开单品项明细ID关联品项表的fl3字段)
  22 +UPDATE lq_kd_kjbsyj kjbsyj
  23 +LEFT JOIN lq_kd_pxmx pxmx ON kjbsyj.F_kdpxid = pxmx.F_Id
  24 +LEFT JOIN lq_xmzl xmzl ON COALESCE(kjbsyj.F_ItemId, pxmx.px) = xmzl.F_Id
  25 +SET kjbsyj.F_PerformanceType = COALESCE(xmzl.fl3, '')
  26 +WHERE (kjbsyj.F_PerformanceType IS NULL OR kjbsyj.F_PerformanceType = '')
  27 + AND kjbsyj.F_IsEffective = 1
  28 + AND xmzl.F_Id IS NOT NULL;
  29 +
  30 +-- 4. 更新消耗品项表(通过品项ID关联品项表的fl3字段)
  31 +UPDATE lq_xh_pxmx pxmx
  32 +INNER JOIN lq_xmzl xmzl ON pxmx.px = xmzl.F_Id
  33 +SET pxmx.F_PerformanceType = COALESCE(xmzl.fl3, '')
  34 +WHERE (pxmx.F_PerformanceType IS NULL OR pxmx.F_PerformanceType = '')
  35 + AND (pxmx.F_IsEffective = 1 OR pxmx.F_IsEffective IS NULL);
  36 +
  37 +-- 5. 更新消耗健康师业绩表(通过品项ID关联品项表的fl3字段)
  38 +UPDATE lq_xh_jksyj jksyj
  39 +LEFT JOIN lq_xh_pxmx pxmx ON jksyj.F_kdpxid = pxmx.F_Id
  40 +LEFT JOIN lq_xmzl xmzl ON COALESCE(jksyj.F_ItemId, pxmx.px) = xmzl.F_Id
  41 +SET jksyj.F_PerformanceType = COALESCE(xmzl.fl3, '')
  42 +WHERE (jksyj.F_PerformanceType IS NULL OR jksyj.F_PerformanceType = '')
  43 + AND (jksyj.F_IsEffective = 1 OR jksyj.F_IsEffective IS NULL)
  44 + AND xmzl.F_Id IS NOT NULL;
  45 +
  46 +-- 6. 更新消耗科技部老师业绩表(通过品项ID关联品项表的fl3字段)
  47 +UPDATE lq_xh_kjbsyj kjbsyj
  48 +LEFT JOIN lq_xh_pxmx pxmx ON kjbsyj.F_hkpxid = pxmx.F_Id
  49 +LEFT JOIN lq_xmzl xmzl ON COALESCE(kjbsyj.F_ItemId, pxmx.px) = xmzl.F_Id
  50 +SET kjbsyj.F_PerformanceType = COALESCE(xmzl.fl3, '')
  51 +WHERE (kjbsyj.F_PerformanceType IS NULL OR kjbsyj.F_PerformanceType = '')
  52 + AND (kjbsyj.F_IsEffective = 1 OR kjbsyj.F_IsEffective IS NULL)
  53 + AND xmzl.F_Id IS NOT NULL;
  54 +
  55 +-- 7. 更新退卡明细表(通过品项ID关联品项表的fl3字段)
  56 +UPDATE lq_hytk_mx mx
  57 +INNER JOIN lq_xmzl xmzl ON mx.px = xmzl.F_Id
  58 +SET mx.F_PerformanceType = COALESCE(xmzl.fl3, '')
  59 +WHERE (mx.F_PerformanceType IS NULL OR mx.F_PerformanceType = '')
  60 + AND mx.F_IsEffective = 1;
  61 +
  62 +-- 8. 更新退卡健康师业绩表(通过品项ID关联品项表的fl3字段)
  63 +UPDATE lq_hytk_jksyj jksyj
  64 +LEFT JOIN lq_hytk_mx mx ON jksyj.F_CardReturn = mx.F_Id
  65 +LEFT JOIN lq_xmzl xmzl ON COALESCE(jksyj.F_ItemId, mx.px) = xmzl.F_Id
  66 +SET jksyj.F_PerformanceType = COALESCE(xmzl.fl3, '')
  67 +WHERE (jksyj.F_PerformanceType IS NULL OR jksyj.F_PerformanceType = '')
  68 + AND jksyj.F_IsEffective = 1
  69 + AND xmzl.F_Id IS NOT NULL;
  70 +
  71 +-- 9. 更新退卡科技部老师业绩表(通过品项ID关联品项表的fl3字段)
  72 +UPDATE lq_hytk_kjbsyj kjbsyj
  73 +LEFT JOIN lq_hytk_mx mx ON kjbsyj.F_CardReturn = mx.F_Id
  74 +LEFT JOIN lq_xmzl xmzl ON COALESCE(kjbsyj.F_ItemId, mx.px) = xmzl.F_Id
  75 +SET kjbsyj.F_PerformanceType = COALESCE(xmzl.fl3, '')
  76 +WHERE (kjbsyj.F_PerformanceType IS NULL OR kjbsyj.F_PerformanceType = '')
  77 + AND kjbsyj.F_IsEffective = 1
  78 + AND xmzl.F_Id IS NOT NULL;
  79 +
  80 +-- 10. 更新业绩明细表(lq_yjmxb)
  81 +-- 业绩明细表通常是汇总表,可能包含开单和消耗的数据
  82 +-- 由于无法准确判断每条记录的具体来源,这里先设置为空
  83 +-- 如果需要更精确的更新,可以根据业务逻辑关联其他表来判断
  84 +-- 例如:如果业绩明细表有开单编号字段,可以关联开单表判断为'开单'
  85 +-- 如果业绩明细表有耗卡编号字段,可以关联耗卡表判断为'消耗'
  86 +UPDATE lq_yjmxb
  87 +SET F_PerformanceType = NULL
  88 +WHERE F_PerformanceType IS NULL OR F_PerformanceType = '';
  89 +
  90 +-- 注意:如果业绩明细表有明确的关联字段,可以使用以下逻辑进行更精确的更新:
  91 +-- UPDATE lq_yjmxb yj
  92 +-- LEFT JOIN lq_kd_kdjlb kd ON yj.关联字段 = kd.F_Id
  93 +-- LEFT JOIN lq_xh_hyhk xh ON yj.关联字段 = xh.F_Id
  94 +-- SET yj.F_PerformanceType = CASE
  95 +-- WHEN kd.F_Id IS NOT NULL THEN '开单'
  96 +-- WHEN xh.F_Id IS NOT NULL THEN '消耗'
  97 +-- ELSE NULL
  98 +-- END
  99 +-- WHERE yj.F_PerformanceType IS NULL OR yj.F_PerformanceType = '';
  100 +
  101 +-- 验证更新结果(统计各表的业绩类型分布)
  102 +SELECT
  103 + 'lq_kd_pxmx' as table_name,
  104 + COUNT(*) as total_count,
  105 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  106 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  107 +FROM lq_kd_pxmx
  108 +WHERE F_IsEffective = 1
  109 +UNION ALL
  110 +SELECT
  111 + 'lq_kd_jksyj' as table_name,
  112 + COUNT(*) as total_count,
  113 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  114 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  115 +FROM lq_kd_jksyj
  116 +WHERE F_IsEffective = 1
  117 +UNION ALL
  118 +SELECT
  119 + 'lq_kd_kjbsyj' as table_name,
  120 + COUNT(*) as total_count,
  121 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  122 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  123 +FROM lq_kd_kjbsyj
  124 +WHERE F_IsEffective = 1
  125 +UNION ALL
  126 +SELECT
  127 + 'lq_xh_pxmx' as table_name,
  128 + COUNT(*) as total_count,
  129 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  130 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  131 +FROM lq_xh_pxmx
  132 +WHERE F_IsEffective = 1 OR F_IsEffective IS NULL
  133 +UNION ALL
  134 +SELECT
  135 + 'lq_xh_jksyj' as table_name,
  136 + COUNT(*) as total_count,
  137 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  138 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  139 +FROM lq_xh_jksyj
  140 +WHERE F_IsEffective = 1 OR F_IsEffective IS NULL
  141 +UNION ALL
  142 +SELECT
  143 + 'lq_xh_kjbsyj' as table_name,
  144 + COUNT(*) as total_count,
  145 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  146 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  147 +FROM lq_xh_kjbsyj
  148 +WHERE F_IsEffective = 1 OR F_IsEffective IS NULL
  149 +UNION ALL
  150 +SELECT
  151 + 'lq_hytk_mx' as table_name,
  152 + COUNT(*) as total_count,
  153 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  154 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  155 +FROM lq_hytk_mx
  156 +WHERE F_IsEffective = 1
  157 +UNION ALL
  158 +SELECT
  159 + 'lq_hytk_jksyj' as table_name,
  160 + COUNT(*) as total_count,
  161 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  162 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  163 +FROM lq_hytk_jksyj
  164 +WHERE F_IsEffective = 1
  165 +UNION ALL
  166 +SELECT
  167 + 'lq_hytk_kjbsyj' as table_name,
  168 + COUNT(*) as total_count,
  169 + SUM(CASE WHEN F_PerformanceType IS NOT NULL AND F_PerformanceType != '' THEN 1 ELSE 0 END) as '已设置',
  170 + SUM(CASE WHEN F_PerformanceType IS NULL OR F_PerformanceType = '' THEN 1 ELSE 0 END) as '未设置'
  171 +FROM lq_hytk_kjbsyj
  172 +WHERE F_IsEffective = 1;
  173 +
  174 +-- 查看业绩类型的值分布(从品项表fl3字段)
  175 +SELECT
  176 + 'lq_xmzl.fl3 值分布' as description,
  177 + fl3 as performance_type,
  178 + COUNT(*) as count
  179 +FROM lq_xmzl
  180 +WHERE fl3 IS NOT NULL AND fl3 != ''
  181 +GROUP BY fl3
  182 +ORDER BY count DESC;
  183 +
... ...
sql/添加业绩类型字段.sql 0 → 100644
  1 +-- 添加业绩类型字段到相关表
  2 +-- 字段名:F_PerformanceType
  3 +-- 字段类型:varchar(50)
  4 +-- 字段说明:业绩类型
  5 +
  6 +-- 1. 开单品项表
  7 +ALTER TABLE lq_kd_pxmx
  8 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_ActivityId;
  9 +
  10 +-- 2. 开单健康师业绩表
  11 +ALTER TABLE lq_kd_jksyj
  12 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_ItemName;
  13 +
  14 +-- 3. 开单科技部老师业绩表
  15 +ALTER TABLE lq_kd_kjbsyj
  16 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_ItemName;
  17 +
  18 +-- 4. 消耗品项表
  19 +ALTER TABLE lq_xh_pxmx
  20 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_IsEffective;
  21 +
  22 +-- 5. 消耗健康师业绩表
  23 +ALTER TABLE lq_xh_jksyj
  24 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_ItemName;
  25 +
  26 +-- 6. 消耗科技部老师业绩表
  27 +ALTER TABLE lq_xh_kjbsyj
  28 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_ItemName;
  29 +
  30 +-- 7. 退卡明细表
  31 +ALTER TABLE lq_hytk_mx
  32 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_IsEffective;
  33 +
  34 +-- 8. 退卡健康师业绩表
  35 +ALTER TABLE lq_hytk_jksyj
  36 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_ItemName;
  37 +
  38 +-- 9. 退卡科技部老师业绩表
  39 +ALTER TABLE lq_hytk_kjbsyj
  40 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER F_ItemName;
  41 +
  42 +-- 10. 业绩明细表
  43 +ALTER TABLE lq_yjmxb
  44 +ADD COLUMN F_PerformanceType VARCHAR(50) NULL COMMENT '业绩类型' AFTER zyj;
  45 +
... ...