serviceImprovementRule.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. <template>
  2. <div>
  3. <el-button size="small" style="width:120px" type="primary" @click="openDialog">{{ $t('设 置') }}</el-button>
  4. <el-dialog :title="$t(`服务改善自动创建规则`)" append-to-body :visible.sync="dialogVisible" width="860px">
  5. <div style="margin-bottom: 16px;">
  6. <div style="display: flex; justify-content: space-between; align-items: center;">
  7. <span style="font-weight: bold;">{{ $t('设置真因分析产品经理') }}</span>
  8. <el-button type="primary" size="mini" @click="addRow">{{ $t('添加行') }}</el-button>
  9. </div>
  10. </div>
  11. <el-table :data="tableData" style="width: 100%" border size="small">
  12. <el-table-column :label="$t('产品经理')" prop="name">
  13. <template slot-scope="scope" >
  14. <el-popover
  15. v-if="scope.row.timestamp"
  16. placement="bottom-start"
  17. width="600"
  18. v-model="scope.row.popoverVisible"
  19. trigger="click"
  20. @show="resetParam"
  21. >
  22. <el-input
  23. v-model="managerParam.content.where.condition"
  24. :placeholder="$t('搜索')"
  25. size="small"
  26. class="mb-10"
  27. @keyup.native.enter="searchManager"
  28. @clear="searchManager"
  29. clearable
  30. >
  31. <i slot="suffix" class="el-input__icon el-icon-search" @click="searchManager"></i>
  32. </el-input>
  33. <tableTemplate
  34. v-if="scope.row.popoverVisible"
  35. ref="managerTable"
  36. :layout="managerTableCols"
  37. :param="managerParam"
  38. :isInput="false"
  39. :isPagination="true"
  40. :height="'300px'"
  41. size="mini"
  42. @rowClick="(val) => handleManagerSelect(val, scope.row)"
  43. />
  44. <el-input
  45. slot="reference"
  46. v-model="scope.row.name"
  47. :placeholder="$t('请选择')"
  48. readonly
  49. style="width: 100%"
  50. size="mini"
  51. />
  52. </el-popover>
  53. <span v-else>{{ scope.row.name }}</span>
  54. </template>
  55. </el-table-column>
  56. <el-table-column :label="$t('商品型号')">
  57. <template slot-scope="scope">
  58. <el-popover
  59. v-if="scope.row.timestamp"
  60. placement="bottom-start"
  61. width="600"
  62. v-model="scope.row.modelPopoverVisible"
  63. trigger="click"
  64. @show="resetModelParam(scope.row, scope.$index)"
  65. >
  66. <el-input
  67. v-model="modelParam.content.where.condition"
  68. :placeholder="$t('搜索')"
  69. size="small"
  70. class="mb-10"
  71. @keyup.native.enter="searchModel(scope.row, scope.$index)"
  72. @clear="searchModel(scope.row, scope.$index)"
  73. clearable
  74. >
  75. <i slot="suffix" class="el-input__icon el-icon-search" @click="searchModel(scope.row, scope.$index)"></i>
  76. </el-input>
  77. <tableTemplate
  78. v-if="scope.row.modelPopoverVisible"
  79. ref="modelTable"
  80. :layout="modelTableCols"
  81. :param="modelParam"
  82. :isInput="false"
  83. :isPagination="true"
  84. :height="'300px'"
  85. size="mini"
  86. :checkbox="true"
  87. :rowKey="getModelValue"
  88. :reserveSelection="true"
  89. @selectionChange="(val) => handleModelSelectionChange(val, scope.row)"
  90. @listData="(val) => syncModelSelection(val, scope.row, scope.$index)"
  91. />
  92. <el-input
  93. slot="reference"
  94. :value="formatModelLabel(scope.row.productModel)"
  95. :placeholder="$t('请选择')"
  96. readonly
  97. @click.native="modelParam.content.hrid = scope.row.hrid"
  98. style="width: 100%"
  99. size="mini"
  100. />
  101. </el-popover>
  102. <span v-else>{{ formatModelLabel(scope.row.productModel) || $t('未选择') }}</span>
  103. </template>
  104. </el-table-column>
  105. <el-table-column :label="$t('操作')" width="100" align="center">
  106. <template slot-scope="scope">
  107. <el-button type="text" size="mini" @click="deleteRow(scope.row, scope.$index)">{{ $t('删除') }}</el-button>
  108. </template>
  109. </el-table-column>
  110. </el-table>
  111. <div class="dialog-footer" style="margin-top: 20px; text-align: right;">
  112. <el-button size="small" @click="dialogVisible = false" class="normal-btn-width">{{$t('取 消')}}</el-button>
  113. <el-button size="small" type="primary" class="normal-btn-width" @click="onSubmit">{{$t('确 定')}}</el-button>
  114. </div>
  115. </el-dialog>
  116. </div>
  117. </template>
  118. <script>
  119. import tableTemplate from '@/template/popoverTable/table'
  120. export default {
  121. name: "serviceImprovementRule",
  122. components: { tableTemplate },
  123. data() {
  124. return {
  125. dialogVisible: false,
  126. tableData: [],
  127. managerOptions: [], // 应该从接口获取
  128. managerTableCols: [
  129. { columnname: 'name', title: this.$t('姓名') },
  130. { columnname: 'depname', title: this.$t('部门') },
  131. { columnname: 'position', title: this.$t('职位') },
  132. { columnname: 'depname', title: this.$t('负责区域') },
  133. { columnname: 'phonenumber', title: this.$t('手机号码') }
  134. ],
  135. modelTableCols: [
  136. { columnname: 'model', title: this.$t('型号') }
  137. ],
  138. managerParam: {
  139. "content": {
  140. "where": {
  141. "condition": ""
  142. },
  143. "pageNumber": 1,
  144. "pageSize": 20
  145. },
  146. "id": 2026011711061202,
  147. },
  148. modelParam: {
  149. "content": {
  150. "where": {
  151. "condition": ""
  152. },
  153. "pageNumber": 1,
  154. "pageSize": 20
  155. },
  156. "id": 2026011710020402,
  157. }
  158. }
  159. },
  160. methods: {
  161. openDialog() {
  162. this.dialogVisible = true;
  163. this.queryData();
  164. },
  165. addRow() {
  166. this.tableData.push({
  167. timestamp: new Date().getTime(),
  168. name: '',
  169. hrid: '',
  170. userid: '',
  171. productModel: [],
  172. popoverVisible: false,
  173. modelPopoverVisible: false
  174. });
  175. },
  176. async deleteRow(row,index) {
  177. console.log(row,index)
  178. if (row.timestamp) {
  179. this.tableData.splice(index, 1)
  180. } else {
  181. this.$confirm(this.$t('确认删除吗?'), this.$t('提示'), {
  182. confirmButtonText: this.$t('确定'),
  183. cancelButtonText: this.$t('取消'),
  184. type: 'warning'
  185. }).then(async () => {
  186. await this.$api.requested({
  187. "content": {
  188. "hrid": row.hrid
  189. },
  190. "id": 2026011710014002,
  191. });
  192. this.tableData.splice(index, 1);
  193. });
  194. }
  195. },
  196. resetParam() {
  197. this.managerParam.content.where.condition = '';
  198. this.managerParam.content.pageNumber = 1;
  199. this.$nextTick(() => {
  200. if (this.$refs.managerTable) {
  201. const tables = Array.isArray(this.$refs.managerTable) ? this.$refs.managerTable : [this.$refs.managerTable];
  202. tables.forEach(table => table.listData());
  203. }
  204. });
  205. },
  206. searchManager() {
  207. this.managerParam.content.pageNumber = 1;
  208. if (this.$refs.managerTable) {
  209. const tables = Array.isArray(this.$refs.managerTable) ? this.$refs.managerTable : [this.$refs.managerTable];
  210. tables.forEach(table => table.listData());
  211. }
  212. },
  213. handleManagerSelect(val, row) {
  214. this.$set(row, 'name', val.name);
  215. this.$set(row, 'hrid', val.hrid);
  216. this.$set(row, 'userid', val.userid);
  217. if (!row.timestamp) {
  218. this.$set(row, 'timestamp', new Date().getTime());
  219. }
  220. row.popoverVisible = false;
  221. },
  222. resetModelParam(row, index) {
  223. this.modelParam.content.where.condition = '';
  224. this.modelParam.content.pageNumber = 1;
  225. this.$nextTick(() => {
  226. const table = this.getTableRef(this.$refs.modelTable, index);
  227. if (table) {
  228. table.listData();
  229. }
  230. });
  231. },
  232. searchModel(row, index) {
  233. this.modelParam.content.pageNumber = 1;
  234. const table = this.getTableRef(this.$refs.modelTable, index);
  235. if (table) {
  236. table.listData();
  237. }
  238. },
  239. handleModelSelectionChange(val, row) {
  240. const models = (val || []).map(item => this.getModelValue(item)).filter(Boolean);
  241. const uniqueModels = models.filter((item, idx) => models.indexOf(item) === idx);
  242. this.$set(row, 'productModel', uniqueModels);
  243. },
  244. syncModelSelection(list, row, index) {
  245. const table = this.getTableRef(this.$refs.modelTable, index);
  246. if (!table || !table.$refs || !table.$refs.table) return;
  247. const selectedKeys = Array.isArray(row.productModel) ? row.productModel : (row.productModel ? [row.productModel] : []);
  248. (list || []).forEach(item => {
  249. const key = this.getModelValue(item);
  250. const shouldBeSelected = selectedKeys.includes(key);
  251. table.$refs.table.toggleRowSelection(item, shouldBeSelected);
  252. });
  253. },
  254. getTableRef(refs, index) {
  255. if (Array.isArray(refs)) {
  256. return refs[index];
  257. }
  258. return refs;
  259. },
  260. getModelValue(item) {
  261. return item.model || item.value || item.label || item.itemno;
  262. },
  263. formatModelLabel(models) {
  264. const list = Array.isArray(models) ? models : (models ? [models] : []);
  265. return list.join('、');
  266. },
  267. async queryData() {
  268. // TODO: 调用接口获取当前配置
  269. const res = await this.$api.requested({
  270. "content": {
  271. "where": {
  272. "condition": ""
  273. },
  274. "pageNumber": 1,
  275. "pageSize": 20
  276. },
  277. "id": 2026011709524202,
  278. });
  279. if (res.code === 1) {
  280. this.tableData = (res.data || []).map(item => ({
  281. ...item,
  282. name: item.name, // 确保有 name 字段
  283. productModel: Array.isArray(item.models) ? item.models : (item.models ? item.models.split(',') : []), // 确保 productModel 是数组
  284. popoverVisible: false,
  285. modelPopoverVisible: false
  286. }));
  287. }
  288. },
  289. async onSubmit() {
  290. // TODO: 调用接口保存配置
  291. const updateRows = this.tableData.filter(item => item.timestamp);
  292. if (updateRows.length === 0) {
  293. this.$message.warning(this.$t('没有可保存的数据'));
  294. return;
  295. }
  296. let successCount = 0;
  297. let failCount = 0;
  298. for (const item of updateRows) {
  299. const res = await this.$api.requested({
  300. "content": {
  301. "hrid": item.hrid,
  302. "userid": item.userid,
  303. "models": item.productModel,
  304. },
  305. "id": 2026011709520902,
  306. });
  307. if (res.code === 1) {
  308. successCount++;
  309. } else {
  310. failCount++;
  311. }
  312. }
  313. if (failCount === 0) {
  314. this.$message.success(this.$t('保存成功'));
  315. this.dialogVisible = false;
  316. this.$emit('queryRule');
  317. } else {
  318. this.$message.warning(this.$t('保存完成,成功 {0} 条,失败 {1} 条', [successCount, failCount]));
  319. // 失败时不关闭,或者刷新列表?这里选择刷新
  320. this.$emit('queryRule');
  321. }
  322. }
  323. }
  324. }
  325. </script>
  326. <style scoped>
  327. .dialog-footer {
  328. text-align: right;
  329. }
  330. </style>