You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1842 lines
63 KiB

3 weeks ago
3 weeks ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
2 months ago
1 month ago
2 months ago
4 weeks ago
4 weeks ago
4 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
1 week ago
4 weeks ago
1 month ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
4 weeks ago
1 month ago
4 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
1 month ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
1 month ago
2 months ago
4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
3 weeks ago
3 weeks ago
2 months ago
4 weeks ago
2 months ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
4 weeks ago
4 weeks ago
1 month ago
1 week ago
4 weeks ago
4 weeks ago
1 month ago
1 week ago
4 weeks ago
4 weeks ago
1 week ago
4 weeks ago
2 months ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
4 weeks ago
4 weeks ago
1 month ago
1 month ago
4 weeks ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
  1. <template>
  2. <div class="customer-css" ref="pageRoot">
  3. <!-- 查询时间和产品 -->
  4. <el-form ref="searchForm" :inline="true" label-position="top" label-width="100px" style="margin-top: 0px;" >
  5. <el-row>
  6. <el-col :span="24" style="">
  7. <el-form-item :label="'产品编码:'">
  8. <!-- <span style="cursor: pointer" slot="label" @click="getBaseList(520)"><a href="#">产品编码</a></span> -->
  9. <el-input v-model="searchData.partNo" style="width: 130px"></el-input>
  10. </el-form-item>
  11. <el-form-item :label="'基准料号:'">
  12. <el-input v-model="searchData.basePartNo" style="width: 130px"></el-input>
  13. </el-form-item>
  14. <!-- <el-form-item :label="'NPC货号:'">-->
  15. <!-- <el-input v-model="searchData.npc" style="width: 130px"></el-input>-->
  16. <!-- </el-form-item>-->
  17. <el-form-item :label="'产品名称:'">
  18. <el-input v-model="searchData.partDesc" style="width: 130px"></el-input>
  19. </el-form-item>
  20. <el-form-item :label="'Item:'">
  21. <el-input v-model="searchData.item" style="width: 130px"></el-input>
  22. </el-form-item>
  23. <el-form-item :label="'SKU:'">
  24. <el-input v-model="searchData.sku" style="width: 130px"></el-input>
  25. </el-form-item>
  26. <el-form-item :label="'默认供应商:'">
  27. <el-input v-model="searchData.defaultSupplierNo" style="width: 130px"></el-input>
  28. </el-form-item>
  29. <el-form-item :label="'一级分类:'">
  30. <el-select v-model="searchData.category" clearable filterable style="width: 130px" @change="onSearchCategoryChange">
  31. <el-option v-for="item in searchCategoryLevel1Options" :key="item.familyId"
  32. :label="item.familyName" :value="item.familyId" />
  33. </el-select>
  34. </el-form-item>
  35. <el-form-item :label="'二级分类:'">
  36. <el-select v-model="searchData.categoryLevel2" clearable filterable style="width: 130px"
  37. :disabled="!searchData.category" @change="onSearchCategoryLevel2Change">
  38. <el-option v-for="item in searchCategoryLevel2Options" :key="item.familyId"
  39. :label="item.familyName" :value="item.familyId" />
  40. </el-select>
  41. </el-form-item>
  42. <el-form-item :label="'三级分类:'">
  43. <el-select v-model="searchData.categoryLevel3" clearable filterable style="width: 130px"
  44. :disabled="!searchData.categoryLevel2">
  45. <el-option v-for="item in searchCategoryLevel3Options" :key="item.familyId"
  46. :label="item.familyName" :value="item.familyId" />
  47. </el-select>
  48. </el-form-item>
  49. <el-form-item :label="' '">
  50. <el-button class="customer-bun-min" type="primary" @click="getMainData" style="">查询</el-button>
  51. <el-button @click="addPart()" type="primary" style="margin-left: 2px">新增</el-button>
  52. <el-button @click="openCopyDialog" type="primary" style="margin-left: 2px">复制</el-button>
  53. </el-form-item>
  54. </el-col>
  55. </el-row>
  56. </el-form>
  57. <el-table
  58. :height="height"
  59. :data="mainDataList"
  60. border
  61. ref="mainTable"
  62. highlight-current-row
  63. @row-click="changeData"
  64. v-loading="dataListLoading"
  65. style="margin-top: 0px; width: 100%;">
  66. <el-table-column
  67. v-for="(item,index) in columnArray1" :key="index"
  68. :sortable="item.columnSortable"
  69. :prop="item.columnProp"
  70. :header-align="item.headerAlign"
  71. :show-overflow-tooltip="item.showOverflowTooltip"
  72. :align="item.align"
  73. :fixed="item.fixed==''?false:item.fixed"
  74. :min-width="item.columnWidth"
  75. :label="item.columnLabel">
  76. <template slot-scope="scope">
  77. <span v-if="!item.columnHidden">{{
  78. formatTableCell(item.columnProp, scope.row)
  79. }}</span>
  80. <span v-if="item.columnImage"><img :src="scope.row[item.columnProp]"
  81. style="width: 100px; height: 100px"/></span>
  82. </template>
  83. </el-table-column>
  84. <!-- 操作列 -->
  85. <el-table-column
  86. fixed="right"
  87. header-align="center"
  88. align="center"
  89. width="200"
  90. label="Action">
  91. <template slot-scope="scope">
  92. <!-- <el-link style="cursor: pointer" v-if="scope.row.flowStatus === 'COMPLETED' || scope.row.flowStatus === 'TERMINATED'" @click="handleRestart(scope.row)">重新审批 |</el-link>
  93. <el-link style="cursor: pointer" v-if="scope.row.flowStatus === 'RUNNING'" @click="openApproveDialog(scope.row)">审批 |</el-link> -->
  94. <el-link style="cursor: pointer" v-if="scope.row.partStage === 'Created'" @click="startFormalApprove(scope.row)">转正 |</el-link>
  95. <el-link style="cursor: pointer" @click="openChangeDefaultSupplier(scope.row)">变更默认供应商 |</el-link>
  96. <el-link style="cursor: pointer" @click="editPart(scope.row)">编辑 |</el-link>
  97. <el-link style="cursor: pointer" @click="deletePart(scope.row)">删除</el-link>
  98. </template>
  99. </el-table-column>
  100. </el-table>
  101. <!-- 分页插件 -->
  102. <el-pagination ref="mainPagination" style="margin-top: 0px"
  103. @size-change="sizeChangeHandle"
  104. @current-change="currentChangeHandle"
  105. :current-page="pageIndex"
  106. :page-sizes="[20, 50, 100, 200, 500]"
  107. :page-size="pageSize"
  108. :total="totalPage"
  109. layout="total, sizes, prev, pager, next, jumper">
  110. </el-pagination>
  111. <el-tabs ref="partTabs" v-model="activeName" style="margin-top: 0px; width: 99%;" @tab-click="tabClick" class="customer-tab" type="border-card">
  112. <el-tab-pane label="基础信息" name="basicInfo" style="">
  113. <basicInfo ref="basicInfo"></basicInfo>
  114. </el-tab-pane>
  115. <el-tab-pane label="规格参数" name="specParams" style="">
  116. <specParams ref="specParams"></specParams>
  117. </el-tab-pane>
  118. <el-tab-pane label="关联供应商" name="suppliers" style="">
  119. <suppliers ref="suppliers"></suppliers>
  120. </el-tab-pane>
  121. <el-tab-pane label="审批与放行" name="approval" style="">
  122. <approval ref="approval"></approval>
  123. </el-tab-pane>
  124. <el-tab-pane label="附件" name="attachments" style="">
  125. <attachments ref="attachments"></attachments>
  126. </el-tab-pane>
  127. </el-tabs>
  128. <Chooselist ref="baseList" @getBaseData="getBaseData"></Chooselist>
  129. <!-- 产品编辑对话框 -->
  130. <!-- 默认弹窗可拖动特殊需求除外 - rqrq -->
  131. <el-dialog :title="isAdd ? '新增产品' : '编辑产品'" :visible.sync="partDialogVisible" width="720px" top="3vh" :close-on-click-modal="false" class="part-dialog" v-drag>
  132. <div class="dialog-content">
  133. <el-form
  134. :model="currentpart"
  135. :rules="partRules"
  136. ref="partForm"
  137. label-position="top"
  138. class="part-form">
  139. <div class="form-section">
  140. <el-row :gutter="24">
  141. <el-col :span="6">
  142. <el-form-item label="基准料号" prop="basePartNo">
  143. <el-input v-model="currentpart.basePartNo" :disabled="!isAdd" @input="syncGeneratedPartNo"></el-input>
  144. </el-form-item>
  145. </el-col>
  146. <el-col :span="6">
  147. <el-form-item label="物料后缀" prop="partSuffix">
  148. <el-input v-model="currentpart.partSuffix" :disabled="!isAdd" @input="syncGeneratedPartNo"></el-input>
  149. </el-form-item>
  150. </el-col>
  151. <el-col :span="6">
  152. <el-form-item label="产品编码" prop="partNo">
  153. <el-input v-model="currentpart.partNo" disabled></el-input>
  154. </el-form-item>
  155. </el-col>
  156. <!-- <el-col :span="6">-->
  157. <!-- <el-form-item label="NPC货号" prop="npc">-->
  158. <!-- <el-input v-model="currentpart.npc"></el-input>-->
  159. <!-- </el-form-item>-->
  160. <!-- </el-col>-->
  161. </el-row>
  162. <el-row :gutter="24">
  163. <el-col :span="6">
  164. <el-form-item>
  165. <span style="cursor: pointer" slot="label" @click="getBaseList(510)"><a href="#">计量单位</a></span>
  166. <el-input v-model="currentpart.unit" ></el-input>
  167. </el-form-item>
  168. </el-col>
  169. <el-col :span="6">
  170. <el-form-item prop="defaultSupplierNo">
  171. <span style="cursor: pointer" slot="label" @click="getBaseList(520)"><a href="#">默认供应商</a></span>
  172. <el-input v-model="currentpart.defaultSupplierNo" ></el-input>
  173. </el-form-item>
  174. </el-col>
  175. <el-col :span="6">
  176. <el-form-item label="Item">
  177. <el-input v-model="currentpart.item"></el-input>
  178. </el-form-item>
  179. </el-col>
  180. <el-col :span="6">
  181. <el-form-item label="SKU">
  182. <el-input v-model="currentpart.sku"></el-input>
  183. </el-form-item>
  184. </el-col>
  185. </el-row>
  186. <el-row :gutter="24">
  187. <el-col :span="6">
  188. <el-form-item label="一级分类">
  189. <el-select v-model="currentpart.category" clearable filterable style="width: 100%" @change="onPartCategoryChange">
  190. <el-option v-for="item in categoryLevel1Options" :key="item.familyId"
  191. :label="item.familyName" :value="item.familyId" />
  192. </el-select>
  193. </el-form-item>
  194. </el-col>
  195. <el-col :span="6">
  196. <el-form-item label="二级分类">
  197. <el-select v-model="currentpart.categoryLevel2" clearable filterable style="width: 100%"
  198. :disabled="!currentpart.category" @change="onPartCategoryLevel2Change">
  199. <el-option v-for="item in categoryLevel2Options" :key="item.familyId"
  200. :label="item.familyName" :value="item.familyId" />
  201. </el-select>
  202. </el-form-item>
  203. </el-col>
  204. <el-col :span="6">
  205. <el-form-item label="三级分类">
  206. <el-select v-model="currentpart.categoryLevel3" clearable filterable style="width: 100%"
  207. :disabled="!currentpart.categoryLevel2">
  208. <el-option v-for="item in categoryLevel3Options" :key="item.familyId"
  209. :label="item.familyName" :value="item.familyId" />
  210. </el-select>
  211. </el-form-item>
  212. </el-col>
  213. </el-row>
  214. <el-row :gutter="24">
  215. <el-col :span="12">
  216. <el-form-item label="产品名称" prop="partDesc">
  217. <el-input v-model="currentpart.partDesc"></el-input>
  218. </el-form-item>
  219. </el-col>
  220. <el-col :span="12">
  221. <el-form-item label="产品规格" prop="partSpec">
  222. <el-input v-model="currentpart.partSpec"></el-input>
  223. </el-form-item>
  224. </el-col>
  225. </el-row>
  226. </div>
  227. <div class="form-section">
  228. <el-row :gutter="24">
  229. <el-col :span="6">
  230. <el-form-item >
  231. <span style="cursor: pointer" slot="label" @click="getBaseList(529)"><a href="#">采购员</a></span>
  232. <el-input v-model="currentpart.buyerName" ></el-input>
  233. </el-form-item>
  234. </el-col>
  235. <el-col :span="6">
  236. <el-form-item >
  237. <span style="cursor: pointer" slot="label" @click="getBaseList(528)"><a href="#">sourcing专员</a></span>
  238. <el-input v-model="currentpart.sourcingName" ></el-input>
  239. </el-form-item>
  240. </el-col>
  241. <el-col :span="6">
  242. <el-form-item>
  243. <span style="cursor: pointer" slot="label" @click="getBaseList(527)"><a href="#">属性模板</a></span>
  244. <el-input v-model="currentpart.codeNo" ></el-input>
  245. </el-form-item>
  246. </el-col>
  247. <el-col :span="6">
  248. <el-form-item label="是否在用">
  249. <el-select v-model="currentpart.status" placeholder="请选择" >
  250. <el-option label="在用" value="Y"></el-option>
  251. <el-option label="禁用" value="N"></el-option>
  252. </el-select>
  253. </el-form-item>
  254. </el-col>
  255. </el-row>
  256. </div>
  257. <div class="form-section">
  258. <el-row :gutter="24">
  259. <el-col :span="24">
  260. <el-form-item label="备注">
  261. <el-input v-model="currentpart.remark" type="textarea" :rows="2" resize="none" ></el-input>
  262. </el-form-item>
  263. </el-col>
  264. </el-row>
  265. </div>
  266. </el-form>
  267. </div>
  268. <div slot="footer" class="dialog-footer" style="margin-top: 20px">
  269. <el-button type="primary" @click="savePart()">保存</el-button>
  270. <el-button @click="partDialogVisible = false">取消</el-button>
  271. </div>
  272. </el-dialog>
  273. <el-dialog title="复制物料" :visible.sync="copyDialogVisible" width="520px" :close-on-click-modal="false" v-drag>
  274. <el-form :model="copyForm" :rules="copyRules" ref="copyForm" label-position="top">
  275. <el-row :gutter="24">
  276. <el-col :span="12">
  277. <el-form-item label="基准料号" prop="basePartNo">
  278. <el-input v-model="copyForm.basePartNo"></el-input>
  279. </el-form-item>
  280. </el-col>
  281. <el-col :span="12">
  282. <el-form-item label="物料后缀" prop="partSuffix">
  283. <el-input v-model="copyForm.partSuffix"></el-input>
  284. </el-form-item>
  285. </el-col>
  286. </el-row>
  287. </el-form>
  288. <div slot="footer" class="dialog-footer">
  289. <el-button type="primary" @click="confirmCopyPart">确认</el-button>
  290. <el-button @click="copyDialogVisible = false">取消</el-button>
  291. </div>
  292. </el-dialog>
  293. <el-dialog title="变更默认供应商" :visible.sync="changeSupplierDialogVisible" width="560px" :close-on-click-modal="false" v-drag>
  294. <el-form :model="changeSupplierForm" label-position="top">
  295. <el-row :gutter="24">
  296. <el-col :span="12">
  297. <el-form-item label="变更范围">
  298. <el-select v-model="changeSupplierForm.changeMode" style="width: 100%">
  299. <el-option label="按产品编码" value="PART_NO"></el-option>
  300. <el-option label="按基准物料" value="BASE_PART"></el-option>
  301. </el-select>
  302. </el-form-item>
  303. </el-col>
  304. <el-col :span="12">
  305. <el-form-item label="当前供应商编码">
  306. <el-input v-model="changeSupplierForm.currentSupplierNo" disabled></el-input>
  307. </el-form-item>
  308. </el-col>
  309. </el-row>
  310. <el-row :gutter="24">
  311. <el-col :span="24">
  312. <el-form-item label="当前供应商描述">
  313. <el-input v-model="changeSupplierForm.currentSupplierName" disabled></el-input>
  314. </el-form-item>
  315. </el-col>
  316. </el-row>
  317. <el-row :gutter="24">
  318. <el-col :span="24">
  319. <el-form-item>
  320. <span style="cursor: pointer" slot="label" @click="getBaseList(520, '', 'changeSupplier')"><a href="#">目标供应商</a></span>
  321. <el-input
  322. v-model="changeSupplierForm.targetSupplierNo"
  323. readonly
  324. placeholder="请选择目标供应商"
  325. @click.native="getBaseList(520, '', 'changeSupplier')">
  326. <i slot="suffix" class="el-icon-search" style="cursor:pointer" @click.stop="getBaseList(520, '', 'changeSupplier')"></i>
  327. </el-input>
  328. </el-form-item>
  329. </el-col>
  330. </el-row>
  331. </el-form>
  332. <div slot="footer" class="dialog-footer">
  333. <el-button type="primary" :loading="changeSupplierLoading" @click="confirmChangeDefaultSupplier">确认</el-button>
  334. <el-button @click="changeSupplierDialogVisible = false">取消</el-button>
  335. </div>
  336. </el-dialog>
  337. <!-- 审批对话框 - rqrq -->
  338. <!-- <el-dialog
  339. title="审批"
  340. :visible.sync="approveDialogVisible"
  341. width="550px"
  342. :close-on-click-modal="false"
  343. v-drag>
  344. <el-form :model="approveData" label-position="top">
  345. <el-row :gutter="20">
  346. <el-col :span="12">
  347. <el-form-item label="是否特殊放行">
  348. <el-select v-model="approveData.specialRelease" style="width: 100%">
  349. <el-option label="否" value="N"></el-option>
  350. <el-option label="是" value="Y"></el-option>
  351. </el-select>
  352. </el-form-item>
  353. </el-col>
  354. </el-row>
  355. <el-form-item label="审批意见">
  356. <el-input type="textarea" v-model="approveData.comment" :rows="3" placeholder="请输入审批意见"></el-input>
  357. </el-form-item>
  358. </el-form>
  359. <el-footer style="height:40px;margin-top: 60px;text-align:center">
  360. <el-button type="success" @click="submitApprove('APPROVED')" :loading="approveLoading">同意</el-button>
  361. <el-button type="danger" @click="submitApprove('REJECTED')" :loading="approveLoading">驳回</el-button>
  362. <el-button @click="approveDialogVisible = false" :disabled="approveLoading">取消</el-button>
  363. </el-footer>
  364. </el-dialog> -->
  365. </div>
  366. </template>
  367. <script>
  368. /* 组件 */
  369. import {
  370. searchPartList,
  371. createPart,
  372. updatePart,
  373. copyPartByBase,
  374. deletePart,
  375. startPartFormalApprove,
  376. changePartDefaultSupplier
  377. } from '@/api/part/partInfo.js'
  378. import excel from '@/utils/excel-util.js'
  379. import Chooselist from '@/views/modules/common/Chooselist_eam'
  380. import basicInfo from './com_part_BasicInfo'
  381. import specParams from './com_part_SpecParams'
  382. import suppliers from './com_part_Suppliers'
  383. import approval from './com_part_Approval'
  384. import attachments from './com_part_Attachments'
  385. import {
  386. approveNodeInstance,
  387. restartFlowInstance
  388. } from '@/api/workFlow/workFlow.js'
  389. import { listPartFamilyByType } from '@/api/baseInformation/srmPartFamily.js'
  390. import { refreshPropertiesModal as refreshPartPropertiesModal } from '@/api/part/partProperties.js'
  391. export default {
  392. watch: {
  393. searchData: {
  394. deep: true,
  395. handler: function (newV, oldV) {
  396. this.searchData.partNo = this.searchData.partNo.toUpperCase()
  397. this.searchData.npc = this.searchData.npc.toUpperCase()
  398. this.searchData.category = (this.searchData.category || '').toUpperCase()
  399. this.searchData.categoryLevel2 = (this.searchData.categoryLevel2 || '').toUpperCase()
  400. this.searchData.categoryLevel3 = (this.searchData.categoryLevel3 || '').toUpperCase()
  401. this.searchData.unit = this.searchData.unit.toUpperCase()
  402. this.searchData.codeNo = this.searchData.codeNo.toUpperCase()
  403. this.searchData.partDesc = this.searchData.partDesc.toUpperCase()
  404. this.searchData.partSpec = this.searchData.partSpec.toUpperCase()
  405. this.searchData.basePartNo = (this.searchData.basePartNo || '').toUpperCase()
  406. this.searchData.sku = (this.searchData.sku || '').toUpperCase()
  407. this.searchData.item = (this.searchData.item || '').toUpperCase()
  408. this.searchData.defaultSupplierNo = (this.searchData.defaultSupplierNo || '').toUpperCase()
  409. }
  410. },
  411. currentpart: {
  412. deep: true,
  413. handler: function (newV, oldV) {
  414. this.currentpart.partNo = this.currentpart.partNo.toUpperCase()
  415. this.currentpart.npc = this.currentpart.npc.toUpperCase()
  416. this.currentpart.category = (this.currentpart.category || '').toUpperCase()
  417. this.currentpart.categoryLevel2 = (this.currentpart.categoryLevel2 || '').toUpperCase()
  418. this.currentpart.categoryLevel3 = (this.currentpart.categoryLevel3 || '').toUpperCase()
  419. this.currentpart.unit = this.currentpart.unit.toUpperCase()
  420. this.currentpart.codeNo = this.currentpart.codeNo.toUpperCase()
  421. this.currentpart.partDesc = this.currentpart.partDesc.toUpperCase()
  422. this.currentpart.partSpec = this.currentpart.partSpec.toUpperCase()
  423. this.currentpart.basePartNo = (this.currentpart.basePartNo || '').toUpperCase()
  424. this.currentpart.partSuffix = (this.currentpart.partSuffix || '').toUpperCase()
  425. this.currentpart.sku = (this.currentpart.sku || '').toUpperCase()
  426. this.currentpart.item = (this.currentpart.item || '').toUpperCase()
  427. this.currentpart.defaultSupplierNo = (this.currentpart.defaultSupplierNo || '').toUpperCase()
  428. if (this.isAdd) {
  429. this.currentpart.partNo = this.generatePartNo(this.currentpart.basePartNo, this.currentpart.partSuffix)
  430. }
  431. }
  432. }
  433. },
  434. data () {
  435. return {
  436. functionId: this.$route.meta.menuId,
  437. height: 200,
  438. detailHeight: 320,
  439. currentRow: {},
  440. searchData: {
  441. partNo: '',
  442. basePartNo: '',
  443. npc: '',
  444. partDesc: '',
  445. partSpec: '',
  446. sku: '',
  447. item: '',
  448. defaultSupplierNo: '',
  449. buyerName: '',
  450. sourcingName: '',
  451. category: '',
  452. categoryLevel2: '',
  453. categoryLevel3: '',
  454. unit: '',
  455. status: '',
  456. codeNo: '',
  457. createBy: '',
  458. site: this.$store.state.user.site,
  459. page: 1,
  460. limit: 10
  461. },
  462. pageIndex: 1,
  463. pageSize: 50,
  464. totalPage: 0,
  465. searchCategoryLevel1Options: [],
  466. searchCategoryLevel2Options: [],
  467. searchCategoryLevel3Options: [],
  468. categoryLevel1Options: [],
  469. categoryLevel2Options: [],
  470. categoryLevel3Options: [],
  471. tagNo: '',
  472. mainDataList: [],
  473. dataListLoading: false,
  474. activeName: 'basicInfo',
  475. // 审批对话框
  476. approveDialogVisible: false,
  477. approveLoading: false,
  478. approveData: {
  479. applyNo: '',
  480. // nodeCode: '',
  481. // nodeName: '',
  482. // departmentName: '', // 审批部门 - rqrq
  483. // assigneeName: '',
  484. site: '',
  485. orderType: '',
  486. comment: '',
  487. flowCode: '',
  488. flowVersion: null
  489. },
  490. columnArray1: [
  491. {
  492. userId: this.$store.state.user.name,
  493. functionId: this.functionId,
  494. serialNumber: 'partTablePartNo',
  495. tableId: 'partTable',
  496. tableName: '产品信息',
  497. columnProp: 'partNo',
  498. headerAlign: 'center',
  499. align: 'center',
  500. columnLabel: '产品编码',
  501. columnWidth: '100',
  502. columnHidden: false,
  503. columnImage: false,
  504. columnSortable: false,
  505. sortLv: 0,
  506. status: true,
  507. fixed: false
  508. },
  509. {
  510. userId: this.$store.state.user.name,
  511. functionId: this.functionId,
  512. serialNumber: 'partTableBasePartNo',
  513. tableId: 'partTable',
  514. tableName: '产品信息',
  515. columnProp: 'basePartNo',
  516. headerAlign: 'center',
  517. align: 'center',
  518. columnLabel: '基准料号',
  519. columnWidth: '120',
  520. columnHidden: false,
  521. columnImage: false,
  522. columnSortable: false,
  523. sortLv: 0,
  524. status: true,
  525. fixed: false
  526. },
  527. // {
  528. // userId: this.$store.state.user.name,
  529. // functionId: this.functionId,
  530. // serialNumber: 'partTableNpc',
  531. // tableId: 'partTable',
  532. // tableName: '产品信息',
  533. // columnProp: 'npc',
  534. // headerAlign: 'center',
  535. // align: 'center',
  536. // columnLabel: 'NPC货号',
  537. // columnWidth: '100',
  538. // columnHidden: false,
  539. // columnImage: false,
  540. // columnSortable: false,
  541. // sortLv: 0,
  542. // status: true,
  543. // fixed: false
  544. // },
  545. {
  546. userId: this.$store.state.user.name,
  547. functionId: this.functionId,
  548. serialNumber: 'partTableItem',
  549. tableId: 'partTable',
  550. tableName: '产品信息',
  551. columnProp: 'item',
  552. headerAlign: 'center',
  553. align: 'center',
  554. columnLabel: 'Item',
  555. columnWidth: '120',
  556. columnHidden: false,
  557. columnImage: false,
  558. columnSortable: false,
  559. sortLv: 0,
  560. status: true,
  561. fixed: false
  562. },
  563. {
  564. userId: this.$store.state.user.name,
  565. functionId: this.functionId,
  566. serialNumber: 'partTableSku',
  567. tableId: 'partTable',
  568. tableName: '产品信息',
  569. columnProp: 'sku',
  570. headerAlign: 'center',
  571. align: 'center',
  572. columnLabel: 'SKU',
  573. columnWidth: '120',
  574. columnHidden: false,
  575. columnImage: false,
  576. columnSortable: false,
  577. sortLv: 0,
  578. status: true,
  579. fixed: false
  580. },
  581. {
  582. userId: this.$store.state.user.name,
  583. functionId: this.functionId,
  584. serialNumber: 'partTableDefaultSupplierNo',
  585. tableId: 'partTable',
  586. tableName: '产品信息',
  587. columnProp: 'defaultSupplierNo',
  588. headerAlign: 'center',
  589. align: 'center',
  590. columnLabel: '默认供应商',
  591. columnWidth: '120',
  592. columnHidden: false,
  593. columnImage: false,
  594. columnSortable: false,
  595. sortLv: 0,
  596. status: true,
  597. fixed: false
  598. },
  599. {
  600. userId: this.$store.state.user.name,
  601. functionId: this.functionId,
  602. serialNumber: 'partTablePartDesc',
  603. tableId: 'partTable',
  604. tableName: '产品信息',
  605. columnProp: 'partDesc',
  606. headerAlign: 'center',
  607. align: 'left',
  608. columnLabel: '产品名称',
  609. columnWidth: '200',
  610. columnHidden: false,
  611. columnImage: false,
  612. columnSortable: false,
  613. sortLv: 0,
  614. status: true,
  615. fixed: false
  616. },
  617. {
  618. userId: this.$store.state.user.name,
  619. functionId: this.functionId,
  620. serialNumber: 'partTablepartSpec',
  621. tableId: 'partTable',
  622. tableName: '产品信息',
  623. columnProp: 'partSpec',
  624. headerAlign: 'center',
  625. align: 'left',
  626. columnLabel: '产品规格',
  627. columnWidth: '150',
  628. columnHidden: false,
  629. columnImage: false,
  630. columnSortable: false,
  631. sortLv: 0,
  632. status: true,
  633. fixed: false
  634. },
  635. {
  636. userId: this.$store.state.user.name,
  637. functionId: this.functionId,
  638. serialNumber: 'partTableBuyerName',
  639. tableId: 'partTable',
  640. tableName: '产品信息',
  641. columnProp: 'buyerName',
  642. headerAlign: 'center',
  643. align: 'center',
  644. columnLabel: '采购员',
  645. columnWidth: '100',
  646. columnHidden: false,
  647. columnImage: false,
  648. columnSortable: false,
  649. sortLv: 0,
  650. status: true,
  651. fixed: false
  652. },
  653. {
  654. userId: this.$store.state.user.name,
  655. functionId: this.functionId,
  656. serialNumber: 'partTableSourcingName',
  657. tableId: 'partTable',
  658. tableName: '产品信息',
  659. columnProp: 'sourcingName',
  660. headerAlign: 'center',
  661. align: 'center',
  662. columnLabel: 'sourcing专员',
  663. columnWidth: '100',
  664. columnHidden: false,
  665. columnImage: false,
  666. columnSortable: false,
  667. sortLv: 0,
  668. status: true,
  669. fixed: false
  670. },
  671. {
  672. userId: this.$store.state.user.name,
  673. functionId: this.functionId,
  674. serialNumber: 'partTableCategory',
  675. tableId: 'partTable',
  676. tableName: '产品信息',
  677. columnProp: 'categoryName',
  678. headerAlign: 'center',
  679. align: 'center',
  680. columnLabel: '一级分类',
  681. columnWidth: '100',
  682. columnHidden: false,
  683. columnImage: false,
  684. columnSortable: false,
  685. sortLv: 0,
  686. status: true,
  687. fixed: false
  688. },
  689. {
  690. userId: this.$store.state.user.name,
  691. functionId: this.functionId,
  692. serialNumber: 'partTableCategoryLevel2',
  693. tableId: 'partTable',
  694. tableName: '产品信息',
  695. columnProp: 'categoryLevel2Name',
  696. headerAlign: 'center',
  697. align: 'center',
  698. columnLabel: '二级分类',
  699. columnWidth: '100',
  700. columnHidden: false,
  701. columnImage: false,
  702. columnSortable: false,
  703. sortLv: 0,
  704. status: true,
  705. fixed: false
  706. },
  707. {
  708. userId: this.$store.state.user.name,
  709. functionId: this.functionId,
  710. serialNumber: 'partTableCategoryLevel3',
  711. tableId: 'partTable',
  712. tableName: '产品信息',
  713. columnProp: 'categoryLevel3Name',
  714. headerAlign: 'center',
  715. align: 'center',
  716. columnLabel: '三级分类',
  717. columnWidth: '100',
  718. columnHidden: false,
  719. columnImage: false,
  720. columnSortable: false,
  721. sortLv: 0,
  722. status: true,
  723. fixed: false
  724. },
  725. {
  726. userId: this.$store.state.user.name,
  727. functionId: this.functionId,
  728. serialNumber: 'partTableUnit',
  729. tableId: 'partTable',
  730. tableName: '产品信息',
  731. columnProp: 'unit',
  732. headerAlign: 'center',
  733. align: 'center',
  734. columnLabel: '计量单位',
  735. columnWidth: '80',
  736. columnHidden: false,
  737. columnImage: false,
  738. columnSortable: false,
  739. sortLv: 0,
  740. status: true,
  741. fixed: false
  742. },
  743. {
  744. userId: this.$store.state.user.name,
  745. functionId: this.functionId,
  746. serialNumber: 'partTablePartStage',
  747. tableId: 'partTable',
  748. tableName: '产品信息',
  749. columnProp: 'partStage',
  750. headerAlign: 'center',
  751. align: 'center',
  752. columnLabel: '物料阶段',
  753. columnWidth: '100',
  754. columnHidden: false,
  755. columnImage: false,
  756. columnSortable: false,
  757. sortLv: 0,
  758. status: true,
  759. fixed: false
  760. },
  761. {
  762. userId: this.$store.state.user.name,
  763. functionId: this.functionId,
  764. serialNumber: 'partTableStatus',
  765. tableId: 'partTable',
  766. tableName: '产品信息',
  767. columnProp: 'status',
  768. headerAlign: 'center',
  769. align: 'center',
  770. columnLabel: '是否在用',
  771. columnWidth: '80',
  772. columnHidden: false,
  773. columnImage: false,
  774. columnSortable: false,
  775. sortLv: 0,
  776. status: true,
  777. fixed: false
  778. },
  779. {
  780. userId: this.$store.state.user.name,
  781. functionId: this.functionId,
  782. serialNumber: 'partTableCodeNo',
  783. tableId: 'partTable',
  784. tableName: '产品信息',
  785. columnProp: 'codeNo',
  786. headerAlign: 'center',
  787. align: 'center',
  788. columnLabel: '属性模板',
  789. columnWidth: '100',
  790. columnHidden: false,
  791. columnImage: false,
  792. columnSortable: false,
  793. sortLv: 0,
  794. status: true,
  795. fixed: false
  796. },
  797. {
  798. userId: this.$store.state.user.name,
  799. functionId: this.functionId,
  800. serialNumber: 'partTableCreateBy',
  801. tableId: 'partTable',
  802. tableName: '产品信息',
  803. columnProp: 'createBy',
  804. headerAlign: 'center',
  805. align: 'center',
  806. columnLabel: '创建人',
  807. columnWidth: '100',
  808. columnHidden: false,
  809. columnImage: false,
  810. columnSortable: false,
  811. sortLv: 0,
  812. status: true,
  813. fixed: false
  814. }
  815. // {
  816. // userId: this.$store.state.user.name,
  817. // functionId: this.functionId,
  818. // serialNumber: 'partTableDepartmentName',
  819. // tableId: 'partTable',
  820. // tableName: '产品信息',
  821. // columnProp: 'departmentName',
  822. // headerAlign: 'center',
  823. // align: 'center',
  824. // columnLabel: '审批部门',
  825. // columnWidth: '100',
  826. // columnHidden: false,
  827. // columnImage: false,
  828. // columnSortable: false,
  829. // sortLv: 0,
  830. // status: true,
  831. // fixed: false
  832. // },
  833. // {
  834. // userId: this.$store.state.user.name,
  835. // functionId: this.functionId,
  836. // serialNumber: 'partTableApproverName',
  837. // tableId: 'partTable',
  838. // tableName: '产品信息',
  839. // columnProp: 'assigneeName',
  840. // headerAlign: 'center',
  841. // align: 'center',
  842. // columnLabel: '要求审批人',
  843. // columnWidth: '100',
  844. // columnHidden: false,
  845. // columnImage: false,
  846. // columnSortable: false,
  847. // sortLv: 0,
  848. // status: true,
  849. // fixed: false
  850. // },
  851. // {
  852. // userId: this.$store.state.user.name,
  853. // functionId: this.functionId,
  854. // serialNumber: 'partTableFlowStatus',
  855. // tableId: 'partTable',
  856. // tableName: '产品信息',
  857. // columnProp: 'flowStatus',
  858. // headerAlign: 'center',
  859. // align: 'center',
  860. // columnLabel: '审批状态',
  861. // columnWidth: '100',
  862. // columnHidden: false,
  863. // columnImage: false,
  864. // columnSortable: false,
  865. // sortLv: 0,
  866. // status: true,
  867. // fixed: false
  868. // }
  869. ],
  870. exportName: '产品信息' + this.dayjs().format('YYYYMMDDHHmmss'),
  871. // 产品对话框相关
  872. partDialogVisible: false,
  873. isAdd: true,
  874. currentpart: {
  875. partNo: '',
  876. basePartNo: '',
  877. partSuffix: '',
  878. npc: '',
  879. partDesc: '',
  880. partSpec: '',
  881. sku: '',
  882. item: '',
  883. defaultSupplierNo: '',
  884. buyerName: '',
  885. sourcingName: '',
  886. category: '',
  887. categoryLevel2: '',
  888. categoryLevel3: '',
  889. unit: '',
  890. status: 'Y',
  891. codeNo: '',
  892. createBy: '',
  893. remark: '',
  894. site: this.$store.state.user.site,
  895. },
  896. partRules: {
  897. partDesc: [
  898. { required: true, message: ' ', trigger: 'blur' }
  899. ],
  900. npc: [
  901. { required: true, message: ' ', trigger: 'blur' }
  902. ],
  903. partSpec: [
  904. { required: true, message: ' ', trigger: 'blur' }
  905. ]
  906. },
  907. copyDialogVisible: false,
  908. copyForm: {
  909. basePartNo: '',
  910. partSuffix: ''
  911. },
  912. changeSupplierDialogVisible: false,
  913. changeSupplierLoading: false,
  914. changeSupplierForm: {
  915. changeMode: 'PART_NO',
  916. partNo: '',
  917. basePartNo: '',
  918. currentSupplierNo: '',
  919. currentSupplierName: '',
  920. targetSupplierNo: '',
  921. targetSupplierName: ''
  922. },
  923. basePickScene: '',
  924. copyRules: {
  925. basePartNo: [
  926. { required: true, message: '请输入基准料号', trigger: 'blur' }
  927. ],
  928. partSuffix: [
  929. { required: true, message: '请输入物料后缀', trigger: 'blur' }
  930. ]
  931. }
  932. }
  933. },
  934. /* 组件 */
  935. components: {
  936. Chooselist,
  937. basicInfo,
  938. specParams,
  939. suppliers,
  940. approval,
  941. attachments
  942. },
  943. created() {
  944. this.loadSearchCategoryLevel1()
  945. this.getMainData()
  946. },
  947. mounted () {
  948. this.handleResize()
  949. window.addEventListener('resize', this.handleResize)
  950. },
  951. beforeDestroy () {
  952. window.removeEventListener('resize', this.handleResize)
  953. },
  954. methods: {
  955. getOuterHeight (el) {
  956. if (!el) return 0
  957. const rect = el.getBoundingClientRect()
  958. const style = window.getComputedStyle(el)
  959. return rect.height + (parseFloat(style.marginTop) || 0) + (parseFloat(style.marginBottom) || 0)
  960. },
  961. handleResize () {
  962. this.$nextTick(() => {
  963. const rootEl = this.$refs.pageRoot || this.$el
  964. if (!rootEl) return
  965. const searchFormEl = this.$refs.searchForm && this.$refs.searchForm.$el
  966. ? this.$refs.searchForm.$el
  967. : this.$refs.searchForm
  968. const paginationEl = this.$refs.mainPagination && this.$refs.mainPagination.$el
  969. ? this.$refs.mainPagination.$el
  970. : this.$refs.mainPagination
  971. const tabsEl = this.$refs.partTabs && this.$refs.partTabs.$el
  972. ? this.$refs.partTabs.$el
  973. : this.$refs.partTabs
  974. const tabsHeaderEl = tabsEl ? tabsEl.querySelector('.el-tabs__header') : null
  975. const viewportBottomGap = 24
  976. const pageTop = rootEl.getBoundingClientRect().top
  977. const availableViewportHeight = window.innerHeight - pageTop - viewportBottomGap
  978. const fixedBlockHeight = this.getOuterHeight(searchFormEl) + this.getOuterHeight(paginationEl) + this.getOuterHeight(tabsHeaderEl) + 22
  979. const splitAvailable = availableViewportHeight - fixedBlockHeight
  980. if (!Number.isFinite(splitAvailable) || splitAvailable <= 0) return
  981. let mainTableHeight
  982. let detailHeight
  983. if (splitAvailable < 520) {
  984. mainTableHeight = Math.max(180, Math.floor(splitAvailable * 0.45))
  985. detailHeight = Math.max(220, splitAvailable - mainTableHeight)
  986. } else {
  987. mainTableHeight = Math.max(220, Math.floor(splitAvailable * 0.42))
  988. detailHeight = splitAvailable - mainTableHeight
  989. if (detailHeight < 320) {
  990. detailHeight = 320
  991. mainTableHeight = Math.max(200, splitAvailable - detailHeight)
  992. }
  993. }
  994. this.height = mainTableHeight
  995. this.detailHeight = detailHeight
  996. this.applyCurrentTabHeight()
  997. this.$nextTick(() => {
  998. if (this.$refs.mainTable && this.$refs.mainTable.doLayout) {
  999. this.$refs.mainTable.doLayout()
  1000. }
  1001. })
  1002. })
  1003. },
  1004. getBasicTabHeight () {
  1005. return Math.max(Number(this.height) - 20, 180)
  1006. },
  1007. getDetailTabHeight (offset = 0) {
  1008. return Math.max(Number(this.detailHeight) - Number(offset || 0), 220)
  1009. },
  1010. applyCurrentTabHeight () {
  1011. if (this.$refs.basicInfo && this.$refs.basicInfo.searchData) {
  1012. this.$refs.basicInfo.searchData.height = this.getBasicTabHeight()
  1013. }
  1014. if (this.$refs.specParams && this.$refs.specParams.setTableHeight) {
  1015. this.$refs.specParams.setTableHeight(this.getDetailTabHeight(70))
  1016. }
  1017. if (this.$refs.suppliers && this.$refs.suppliers.setTableHeight) {
  1018. this.$refs.suppliers.setTableHeight(this.getDetailTabHeight(90))
  1019. }
  1020. if (this.$refs.approval && this.$refs.approval.setTableHeight) {
  1021. this.$refs.approval.setTableHeight(this.getDetailTabHeight(30))
  1022. }
  1023. if (this.$refs.attachments && this.$refs.attachments.setTableHeight) {
  1024. this.$refs.attachments.setTableHeight(this.getDetailTabHeight(90))
  1025. }
  1026. },
  1027. formatPartStageDesc (partStage) {
  1028. if (partStage === 'Approved') {
  1029. return '正式物料'
  1030. }
  1031. if (partStage === 'Approving') {
  1032. return '转正审批中'
  1033. }
  1034. return '新增物料'
  1035. },
  1036. formatTableCell (columnProp, row) {
  1037. if (columnProp === 'partStage') {
  1038. return this.formatPartStageDesc(row.partStage)
  1039. }
  1040. if (columnProp === 'status') {
  1041. return row.status === 'Y' ? '在用' : row.status === 'N' ? '禁用' : row.status
  1042. }
  1043. if (columnProp === 'categoryName') {
  1044. return row.categoryName || row.category || ''
  1045. }
  1046. if (columnProp === 'categoryLevel2Name') {
  1047. return row.categoryLevel2Name || row.categoryLevel2 || ''
  1048. }
  1049. if (columnProp === 'categoryLevel3Name') {
  1050. return row.categoryLevel3Name || row.categoryLevel3 || ''
  1051. }
  1052. return row[columnProp]
  1053. },
  1054. generatePartNo (basePartNo, partSuffix) {
  1055. const base = (basePartNo || '').trim().toUpperCase()
  1056. const suffix = (partSuffix || '').trim().toUpperCase()
  1057. if (!base || !suffix) {
  1058. return ''
  1059. }
  1060. return `${base}-${suffix}`
  1061. },
  1062. syncGeneratedPartNo () {
  1063. if (!this.isAdd) return
  1064. this.currentpart.partNo = this.generatePartNo(this.currentpart.basePartNo, this.currentpart.partSuffix)
  1065. },
  1066. extractBasePartNo (partNo) {
  1067. const value = (partNo || '').trim().toUpperCase()
  1068. if (!value) return ''
  1069. const index = value.indexOf('-')
  1070. return index > 0 ? value.substring(0, index) : value
  1071. },
  1072. extractPartSuffix (partNo) {
  1073. const value = (partNo || '').trim().toUpperCase()
  1074. if (!value) return ''
  1075. const index = value.indexOf('-')
  1076. return index > 0 && index < value.length - 1 ? value.substring(index + 1) : ''
  1077. },
  1078. openCopyDialog () {
  1079. const selectedBasePartNo = (this.currentRow && this.currentRow.basePartNo) ? this.currentRow.basePartNo : ''
  1080. this.copyForm = {
  1081. // 复制弹窗默认带出当前选中行基准料号 - rqrq
  1082. basePartNo: (selectedBasePartNo || '').trim().toUpperCase(),
  1083. partSuffix: ''
  1084. }
  1085. this.copyDialogVisible = true
  1086. this.$nextTick(() => {
  1087. if (this.$refs.copyForm) {
  1088. this.$refs.copyForm.clearValidate()
  1089. }
  1090. })
  1091. },
  1092. confirmCopyPart () {
  1093. this.$refs.copyForm.validate((valid) => {
  1094. if (!valid) return
  1095. const basePartNo = (this.copyForm.basePartNo || '').trim().toUpperCase()
  1096. const partSuffix = (this.copyForm.partSuffix || '').trim().toUpperCase()
  1097. if (partSuffix.includes('-')) {
  1098. this.$message.warning('物料后缀不能包含 "-"')
  1099. return
  1100. }
  1101. copyPartByBase({
  1102. site: this.$store.state.user.site,
  1103. basePartNo,
  1104. partSuffix
  1105. }).then(({ data }) => {
  1106. if (data && data.code === 0) {
  1107. this.$message.success(`复制成功,新产品编码:${data.partNo || this.generatePartNo(basePartNo, partSuffix)}`)
  1108. this.copyDialogVisible = false
  1109. this.getMainData()
  1110. return
  1111. }
  1112. this.$message.error((data && data.msg) || '复制失败')
  1113. }).catch(error => {
  1114. this.$message.error('复制失败: ' + error.message)
  1115. })
  1116. })
  1117. },
  1118. openChangeDefaultSupplier (row) {
  1119. if (!row || !row.partNo) {
  1120. this.$message.warning('请先选择物料')
  1121. return
  1122. }
  1123. this.changeSupplierForm = {
  1124. changeMode: 'PART_NO',
  1125. partNo: (row.partNo || '').trim().toUpperCase(),
  1126. basePartNo: (row.basePartNo || '').trim().toUpperCase(),
  1127. currentSupplierNo: (row.defaultSupplierNo || '').trim().toUpperCase(),
  1128. currentSupplierName: row.defaultSupplierName || '',
  1129. targetSupplierNo: '',
  1130. targetSupplierName: ''
  1131. }
  1132. this.changeSupplierDialogVisible = true
  1133. },
  1134. confirmChangeDefaultSupplier () {
  1135. const targetSupplierNo = (this.changeSupplierForm.targetSupplierNo || '').trim().toUpperCase()
  1136. const currentSupplierNo = (this.changeSupplierForm.currentSupplierNo || '').trim().toUpperCase()
  1137. if (!targetSupplierNo) {
  1138. this.$message.warning('目标供应商不能为空')
  1139. return
  1140. }
  1141. if (targetSupplierNo === currentSupplierNo) {
  1142. this.$message.warning('目标供应商不能与当前供应商相同')
  1143. return
  1144. }
  1145. const payload = {
  1146. site: this.$store.state.user.site,
  1147. partNo: this.changeSupplierForm.partNo,
  1148. changeMode: this.changeSupplierForm.changeMode,
  1149. targetSupplierNo
  1150. }
  1151. this.changeSupplierLoading = true
  1152. changePartDefaultSupplier(payload).then(({ data }) => {
  1153. if (data && data.code === 0) {
  1154. const updatedCount = data.updatedCount || 0
  1155. this.$message.success(`变更成功,影响 ${updatedCount} 条物料`)
  1156. this.changeSupplierDialogVisible = false
  1157. this.getMainData()
  1158. return
  1159. }
  1160. this.$message.error((data && data.msg) || '变更失败')
  1161. }).catch(error => {
  1162. this.$message.error('变更失败: ' + error.message)
  1163. }).finally(() => {
  1164. this.changeSupplierLoading = false
  1165. })
  1166. },
  1167. startFormalApprove (row) {
  1168. if (!row || !row.partNo) {
  1169. this.$message.warning('未找到有效产品编码')
  1170. return
  1171. }
  1172. // 新增物料阶段手动发起转正审批 - rqrq
  1173. this.$confirm('确认发起该物料的转正流程吗?', '提示', {
  1174. confirmButtonText: '确定',
  1175. cancelButtonText: '取消',
  1176. type: 'warning'
  1177. }).then(() => {
  1178. let inData = {
  1179. site: this.$store.state.user.site,
  1180. partNo: row.partNo
  1181. }
  1182. startPartFormalApprove(inData).then(({ data }) => {
  1183. if (data && data.code === 0) {
  1184. this.$message.success(data.msg || '操作成功')
  1185. this.getMainData()
  1186. return
  1187. }
  1188. this.$message.error((data && data.msg) || '发起转正失败')
  1189. }).catch(error => {
  1190. this.$message.error('发起转正失败: ' + error.message)
  1191. })
  1192. }).catch(() => {})
  1193. },
  1194. fetchPartFamilyOptions (familyType, parentPartFamily) {
  1195. return listPartFamilyByType({
  1196. site: this.$store.state.user.site,
  1197. familyType,
  1198. parentPartFamily: parentPartFamily || '',
  1199. active: 'Y'
  1200. }).then(({ data }) => {
  1201. if (data && data.code === 0) {
  1202. return data.list || []
  1203. }
  1204. return []
  1205. }).catch(() => [])
  1206. },
  1207. loadSearchCategoryLevel1 () {
  1208. this.fetchPartFamilyOptions('level1').then(list => {
  1209. this.searchCategoryLevel1Options = list
  1210. })
  1211. },
  1212. onSearchCategoryChange () {
  1213. this.searchData.categoryLevel2 = ''
  1214. this.searchData.categoryLevel3 = ''
  1215. this.searchCategoryLevel2Options = []
  1216. this.searchCategoryLevel3Options = []
  1217. if (!this.searchData.category) return
  1218. this.fetchPartFamilyOptions('level2', this.searchData.category).then(list => {
  1219. this.searchCategoryLevel2Options = list
  1220. })
  1221. },
  1222. onSearchCategoryLevel2Change () {
  1223. this.searchData.categoryLevel3 = ''
  1224. this.searchCategoryLevel3Options = []
  1225. if (!this.searchData.categoryLevel2) return
  1226. this.fetchPartFamilyOptions('level3', this.searchData.categoryLevel2).then(list => {
  1227. this.searchCategoryLevel3Options = list
  1228. })
  1229. },
  1230. loadPartCategoryLevel1 () {
  1231. return this.fetchPartFamilyOptions('level1').then(list => {
  1232. this.categoryLevel1Options = list
  1233. })
  1234. },
  1235. loadPartCategoryLevel2 (keepValues) {
  1236. if (!this.currentpart.category) {
  1237. this.categoryLevel2Options = []
  1238. if (!keepValues) {
  1239. this.currentpart.categoryLevel2 = ''
  1240. this.currentpart.categoryLevel3 = ''
  1241. this.categoryLevel3Options = []
  1242. }
  1243. return Promise.resolve()
  1244. }
  1245. return this.fetchPartFamilyOptions('level2', this.currentpart.category).then(list => {
  1246. this.categoryLevel2Options = list
  1247. if (!keepValues) {
  1248. this.currentpart.categoryLevel2 = ''
  1249. this.currentpart.categoryLevel3 = ''
  1250. this.categoryLevel3Options = []
  1251. }
  1252. })
  1253. },
  1254. loadPartCategoryLevel3 (keepValues) {
  1255. if (!this.currentpart.categoryLevel2) {
  1256. this.categoryLevel3Options = []
  1257. if (!keepValues) {
  1258. this.currentpart.categoryLevel3 = ''
  1259. }
  1260. return Promise.resolve()
  1261. }
  1262. return this.fetchPartFamilyOptions('level3', this.currentpart.categoryLevel2).then(list => {
  1263. this.categoryLevel3Options = list
  1264. if (!keepValues) {
  1265. this.currentpart.categoryLevel3 = ''
  1266. }
  1267. })
  1268. },
  1269. onPartCategoryChange () {
  1270. this.loadPartCategoryLevel2(false)
  1271. },
  1272. onPartCategoryLevel2Change () {
  1273. this.loadPartCategoryLevel3(false)
  1274. },
  1275. initPartCategoryOptions (keepValues) {
  1276. return this.loadPartCategoryLevel1().then(() => {
  1277. return this.loadPartCategoryLevel2(keepValues).then(() => {
  1278. return this.loadPartCategoryLevel3(keepValues)
  1279. })
  1280. })
  1281. },
  1282. getBaseList (val, type, scene) {
  1283. this.tagNo = val
  1284. this.basePickScene = scene || ''
  1285. this.$nextTick(() => {
  1286. let strVal = ''
  1287. if (this.tagNo === 510) {
  1288. strVal = this.currentpart.unit
  1289. }
  1290. if (val === 529) {
  1291. strVal = this.currentpart.buyerName
  1292. }
  1293. if (val === 528) {
  1294. strVal = this.currentpart.sourcingName
  1295. }
  1296. if (val === 527) {
  1297. strVal = this.currentpart.codeNo
  1298. }
  1299. if (val === 520) {
  1300. strVal = this.currentpart.defaultSupplierNo
  1301. }
  1302. if (val === 520 && this.basePickScene === 'changeSupplier') {
  1303. strVal = this.changeSupplierForm.targetSupplierNo
  1304. }
  1305. this.$refs.baseList.init(val, strVal?strVal:'')
  1306. })
  1307. },
  1308. /* 列表方法的回调 */
  1309. getBaseData (val) {
  1310. if (this.tagNo === 510) {
  1311. this.currentpart.unit = val.UMID
  1312. }
  1313. if (this.tagNo === 529) {
  1314. this.currentpart.buyerName = val.UserName
  1315. }
  1316. if (this.tagNo === 528) {
  1317. this.currentpart.sourcingName = val.UserName
  1318. }
  1319. if (this.tagNo === 527) {
  1320. this.currentpart.codeNo = val.code_no
  1321. }
  1322. if (this.tagNo === 520) {
  1323. this.currentpart.defaultSupplierNo = val.supplier_no || ''
  1324. }
  1325. if (this.tagNo === 520 && this.basePickScene === 'changeSupplier') {
  1326. const supplierNo = val.supplier_no || ''
  1327. const supplierName = val.supplier_name || ''
  1328. this.changeSupplierForm.targetSupplierNo = (supplierNo || '').trim().toUpperCase()
  1329. this.changeSupplierForm.targetSupplierName = supplierName || ''
  1330. }
  1331. this.basePickScene = ''
  1332. },
  1333. getMainData () {
  1334. this.searchData.limit = this.pageSize
  1335. this.searchData.page = this.pageIndex
  1336. searchPartList(this.searchData).then(({data}) => {
  1337. if (data.code === 0) {
  1338. // 处理列表数据,确保可以正确显示嵌套属性
  1339. this.mainDataList = data.page.list.map(item => {
  1340. // 方式1:将嵌套属性提取到顶层
  1341. if (item.flowNodeInstanceData) {
  1342. item.departmentName = item.flowNodeInstanceData.departmentName;
  1343. item.assigneeName = item.flowNodeInstanceData.assigneeName;
  1344. } else {
  1345. item.departmentName = '';
  1346. item.assigneeName = '';
  1347. }
  1348. return item;
  1349. });
  1350. // this.mainDataList = data.page.list
  1351. this.pageIndex = data.page.currPage
  1352. this.pageSize = data.page.pageSize
  1353. this.totalPage = data.page.totalCount
  1354. // 判断是否全部存在数据
  1355. if (this.mainDataList.length > 0) {
  1356. // 设置选中行
  1357. this.$refs.mainTable.setCurrentRow(this.mainDataList[0])
  1358. this.changeData(this.mainDataList[0])
  1359. } else {
  1360. this.changeData(null)
  1361. }
  1362. }
  1363. this.dataListLoading = false
  1364. })
  1365. },
  1366. tabClick (tab, event) {
  1367. this.refreshCurrentTabTable()
  1368. },
  1369. // 每页数
  1370. sizeChangeHandle (val) {
  1371. this.pageSize = val
  1372. this.pageIndex = 1
  1373. this.getMainData()
  1374. },
  1375. // 当前页
  1376. currentChangeHandle (val) {
  1377. this.pageIndex = val
  1378. this.getMainData()
  1379. },
  1380. changeData (row) {
  1381. this.currentRow = JSON.parse(JSON.stringify(row))
  1382. this.refreshCurrentTabTable()
  1383. },
  1384. refreshCurrentTabTable () {
  1385. if (this.currentRow === '' || this.currentRow === null) {
  1386. this.currentRow = {site: '', partNo: ''}
  1387. }
  1388. if (this.activeName === 'basicInfo') {
  1389. this.refreshBasicInfo()
  1390. }
  1391. if (this.activeName === 'specParams') {
  1392. this.refreshSpecParams()
  1393. }
  1394. if (this.activeName === 'suppliers') {
  1395. this.refreshSuppliers()
  1396. }
  1397. if (this.activeName === 'approval') {
  1398. this.refreshApproval()
  1399. }
  1400. if (this.activeName === 'attachments') {
  1401. this.refreshAttachments()
  1402. }
  1403. },
  1404. async exportExcel () {
  1405. this.searchData.limit = -1
  1406. this.searchData.page = 1
  1407. excel.exportTable({
  1408. url: '/part/searchPartList',
  1409. columnMapping: this.columnArray1,
  1410. mergeSetting: [],
  1411. params: this.searchData,
  1412. fileName: this.exportName + '.xlsx',
  1413. rowFetcher: res => res.data,
  1414. columnFormatter: [
  1415. { columnProp: 'partStage', formatter: (val) => this.formatPartStageDesc(val) }
  1416. ],
  1417. dropColumns: []
  1418. })
  1419. },
  1420. refreshBasicInfo () {
  1421. let inData = {
  1422. site: this.currentRow.site,
  1423. partNo: this.currentRow.partNo,
  1424. partDesc: this.currentRow.partDesc,
  1425. height: this.getBasicTabHeight()
  1426. }
  1427. this.$refs.basicInfo.init(inData)
  1428. },
  1429. refreshSpecParams () {
  1430. let inData = {
  1431. site: this.currentRow.site,
  1432. partNo: this.currentRow.partNo,
  1433. codeNo: this.currentRow.codeNo,
  1434. functionType:"P",
  1435. height: this.getDetailTabHeight(70)
  1436. }
  1437. this.$refs.specParams.init(inData)
  1438. },
  1439. refreshSuppliers () {
  1440. let inData = {
  1441. site: this.currentRow.site,
  1442. partNo: this.currentRow.partNo,
  1443. height: this.getDetailTabHeight(90)
  1444. }
  1445. this.$refs.suppliers.init(inData)
  1446. },
  1447. refreshApproval () {
  1448. let inData = {
  1449. site: this.currentRow.site,
  1450. orderRef1: this.currentRow.partNo,
  1451. orderType: '产品资料',
  1452. height: this.getDetailTabHeight(30)
  1453. }
  1454. this.$refs.approval.init(inData)
  1455. },
  1456. refreshAttachments () {
  1457. let inData = {
  1458. orderRef1: this.currentRow.site,
  1459. orderRef2: this.currentRow.partNo,
  1460. orderRef3: this.currentRow.partDesc,
  1461. orderReftype: 'part',
  1462. height: this.getDetailTabHeight(90)
  1463. }
  1464. this.$refs.attachments.init(inData)
  1465. },
  1466. // 新增产品
  1467. addPart() {
  1468. this.isAdd = true
  1469. this.currentpart = {
  1470. partNo: '',
  1471. basePartNo: '',
  1472. partSuffix: '',
  1473. npc: '',
  1474. partDesc: '',
  1475. partSpec: '',
  1476. sku: '',
  1477. item: '',
  1478. defaultSupplierNo: '',
  1479. buyerName: '',
  1480. sourcingName: '',
  1481. category: '',
  1482. categoryLevel2: '',
  1483. categoryLevel3: '',
  1484. unit: '',
  1485. status: 'Y',
  1486. codeNo: '',
  1487. createBy: this.$store.state.user.name,
  1488. remark: '',
  1489. site: this.$store.state.user.site,
  1490. }
  1491. this.categoryLevel2Options = []
  1492. this.categoryLevel3Options = []
  1493. this.loadPartCategoryLevel1()
  1494. this.partDialogVisible = true
  1495. },
  1496. // 编辑产品
  1497. editPart(row) {
  1498. if (!row) {
  1499. this.$message.warning('请选择一个产品修改')
  1500. return
  1501. }
  1502. this.isAdd = false
  1503. this.currentpart = {...row}
  1504. // 编辑时基准料号以原值为准,空值保持为空 - rqrq
  1505. this.currentpart.partSuffix = this.extractPartSuffix(this.currentpart.partNo)
  1506. this.initPartCategoryOptions(true).then(() => {
  1507. this.partDialogVisible = true
  1508. })
  1509. },
  1510. // 新增后自动刷新属性模板 - rqrq
  1511. autoRefreshPartPropertiesAfterCreate () {
  1512. const site = (this.$store.state.user.site || '').trim().toUpperCase()
  1513. const partNo = (this.currentpart.partNo || '').trim().toUpperCase()
  1514. const codeNo = (this.currentpart.codeNo || '').trim().toUpperCase()
  1515. if (!site || !partNo || !codeNo) {
  1516. return Promise.resolve(false)
  1517. }
  1518. // 新增料号成功后自动刷新属性模板,提前生成属性 - rqrq
  1519. return refreshPartPropertiesModal({
  1520. site,
  1521. partNo,
  1522. codeNo,
  1523. recordType: 'P'
  1524. }).then(({ data }) => {
  1525. if (data && data.code === 0) {
  1526. return true
  1527. }
  1528. this.$message.warning((data && data.msg) || '刷新属性模板失败')
  1529. return false
  1530. }).catch(error => {
  1531. this.$message.warning('刷新属性模板失败: ' + (error.message || error))
  1532. return false
  1533. })
  1534. },
  1535. // 保存产品
  1536. savePart() {
  1537. if (this.isAdd) {
  1538. const basePartNo = (this.currentpart.basePartNo || '').trim().toUpperCase()
  1539. const partSuffix = (this.currentpart.partSuffix || '').trim().toUpperCase()
  1540. if (!basePartNo || !partSuffix) {
  1541. this.$message.warning('请填写基准料号和物料后缀')
  1542. return
  1543. }
  1544. if (partSuffix.includes('-')) {
  1545. this.$message.warning('物料后缀不能包含 "-"')
  1546. return
  1547. }
  1548. if (!(this.currentpart.defaultSupplierNo || '').trim()) {
  1549. this.$message.warning('请填写默认供应商')
  1550. return
  1551. }
  1552. this.currentpart.defaultSupplierNo = (this.currentpart.defaultSupplierNo || '').trim().toUpperCase()
  1553. this.currentpart.basePartNo = basePartNo
  1554. this.currentpart.partSuffix = partSuffix
  1555. this.currentpart.partNo = this.generatePartNo(basePartNo, partSuffix)
  1556. }
  1557. this.$refs.partForm.validate((valid) => {
  1558. if (valid) {
  1559. const apiCall = this.isAdd ? createPart(this.currentpart) : updatePart(this.currentpart)
  1560. apiCall.then(({data}) => {
  1561. if (data && data.code === 0) {
  1562. const finishSave = (refreshOk) => {
  1563. const successMsg = this.isAdd
  1564. ? (refreshOk ? '新增产品成功,已刷新属性模板' : '新增产品成功')
  1565. : '修改产品成功'
  1566. this.$message.success(successMsg)
  1567. this.partDialogVisible = false
  1568. this.getMainData()
  1569. }
  1570. // 新增后自动执行“刷新属性模板”按钮同等逻辑 - rqrq
  1571. if (this.isAdd) {
  1572. this.autoRefreshPartPropertiesAfterCreate().then((refreshOk) => {
  1573. finishSave(refreshOk)
  1574. })
  1575. return
  1576. }
  1577. finishSave(false)
  1578. } else {
  1579. this.$message.error(data.msg || '操作失败')
  1580. }
  1581. }).catch(error => {
  1582. this.$message.error('操作失败: ' + error.message)
  1583. })
  1584. } else {
  1585. this.$message.warning('请填写必填字段')
  1586. }
  1587. })
  1588. },
  1589. // 删除产品
  1590. deletePart(row) {
  1591. this.$confirm('你确定删除该产品?', '确认删除', {
  1592. confirmButtonText: '确认',
  1593. cancelButtonText: '取消',
  1594. type: 'warning'
  1595. }).then(() => {
  1596. deletePart({
  1597. id: row.id,
  1598. site: row.site,
  1599. partNo: row.partNo
  1600. }).then(({data}) => {
  1601. if (data && data.code === 0) {
  1602. this.$message.success('产品删除成功')
  1603. this.getMainData()
  1604. } else {
  1605. this.$message.error(data.msg || '删除失败')
  1606. }
  1607. }).catch(error => {
  1608. this.$message.error('删除失败: ' + error.message)
  1609. })
  1610. })
  1611. }
  1612. // 打开审批对话框
  1613. // openApproveDialog(row) {
  1614. // this.approveData = {
  1615. // applyNo: row.flowNodeInstanceData.applyNo,
  1616. // site: row.flowNodeInstanceData.site,
  1617. // orderType: row.flowNodeInstanceData.orderType,
  1618. // flowCode: row.flowNodeInstanceData.flowCode,
  1619. // flowVersion: row.flowNodeInstanceData.flowVersion,
  1620. // nodeCode: row.flowNodeInstanceData.nodeCode,
  1621. // comment: ''
  1622. // }
  1623. // this.approveDialogVisible = true
  1624. // },
  1625. // 提交审批
  1626. // submitApprove(action) {
  1627. // if (action === 'REJECTED' && !this.approveData.comment) {
  1628. // this.$message.warning('驳回时必须填写审批意见')
  1629. // return
  1630. // }
  1631. // this.approveLoading = true
  1632. // approveNodeInstance({
  1633. // applyNo: this.approveData.applyNo,
  1634. // nodeCode: this.approveData.nodeCode,
  1635. // site: this.approveData.site,
  1636. // orderType: this.approveData.orderType,
  1637. // specialRelease: this.approveData.specialRelease,
  1638. // action: action,
  1639. // comment: this.approveData.comment
  1640. // }).then(({ data }) => {
  1641. // if (data && data.code === 0) {
  1642. // this.$message.success(action === 'APPROVED' ? '审批通过成功' : '驳回成功')
  1643. // this.approveDialogVisible = false
  1644. // //刷新列表
  1645. // this.getMainData()
  1646. // } else {
  1647. // this.$message.error(data.msg || '操作失败')
  1648. // }
  1649. // }).finally(() => {
  1650. // this.approveLoading = false
  1651. // })
  1652. // },
  1653. // 重新审批 - rqrq
  1654. // handleRestart(row) {
  1655. // this.$confirm('确定要重新发起审批流程吗?', '提示', {
  1656. // confirmButtonText: '确定',
  1657. // cancelButtonText: '取消',
  1658. // type: 'warning'
  1659. // }).then(() => {
  1660. // restartFlowInstance({
  1661. // applyNo: row.applyNo,
  1662. // site: row.site,
  1663. // orderType: row.orderType
  1664. // }).then(({ data }) => {
  1665. // if (data && data.code === 0) {
  1666. // this.$message.success('重新审批成功')
  1667. // this.getMainData()
  1668. // } else {
  1669. // this.$message.error(data.msg || '操作失败')
  1670. // }
  1671. // })
  1672. // }).catch(() => {})
  1673. // }
  1674. }
  1675. }
  1676. </script>
  1677. <!--当前页面的标签样式-->
  1678. <style scoped lang="scss">
  1679. /deep/ .customer-tab .el-tabs__content {
  1680. padding: 5px !important;
  1681. }
  1682. /* 产品对话框整体样式 */
  1683. .part-dialog {
  1684. font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  1685. }
  1686. .part-dialog .el-dialog {
  1687. margin-top: 5vh !important;
  1688. margin-bottom: 5vh !important;
  1689. }
  1690. .part-dialog .el-dialog__header {
  1691. padding: 20px 25px 15px 25px;
  1692. border-bottom: 1px solid #E4E7ED;
  1693. }
  1694. .part-dialog .el-dialog__body {
  1695. padding: 25px 25px 25px 25px;
  1696. max-height: 75vh;
  1697. overflow-y: auto;
  1698. min-height: 400px;
  1699. }
  1700. .dialog-content {
  1701. width: 100%;
  1702. }
  1703. /* 产品表单样式 */
  1704. .part-form {
  1705. width: 100%;
  1706. }
  1707. .part-form .el-form-item {
  1708. margin-bottom: 1px;
  1709. }
  1710. .part-form .el-form-item__label {
  1711. font-weight: 500;
  1712. color: #303133;
  1713. line-height: 32px;
  1714. padding-right: 12px;
  1715. }
  1716. .part-form .el-form-item__content {
  1717. line-height: normal;
  1718. }
  1719. /* 表单分组样式 */
  1720. .form-section {
  1721. margin-bottom: 5px;
  1722. }
  1723. .form-section:last-child {
  1724. margin-bottom: 5px;
  1725. }
  1726. /* 输入框样式 */
  1727. .part-form .el-input,
  1728. .part-form .el-textarea,
  1729. .part-form .el-date-editor {
  1730. width: 100%;
  1731. }
  1732. /* 文本域样式优化 */
  1733. .part-form .el-textarea__inner {
  1734. resize: none;
  1735. font-family: inherit;
  1736. line-height: 1.5;
  1737. }
  1738. /* 对话框底部按钮居中 */
  1739. .dialog-footer-center {
  1740. text-align: center;
  1741. padding: 15px 0 5px 0;
  1742. border-top: 1px solid #E4E7ED;
  1743. margin-top: 15px;
  1744. }
  1745. .dialog-footer-center .el-button {
  1746. margin: 0 10px;
  1747. min-width: 90px;
  1748. height: 36px;
  1749. padding: 0 20px;
  1750. font-size: 14px;
  1751. }
  1752. /* 响应式调整 */
  1753. @media (max-width: 1200px) {
  1754. .part-dialog {
  1755. width: 95% !important;
  1756. }
  1757. .part-dialog .el-dialog__body {
  1758. padding: 20px 20px 15px 20px;
  1759. }
  1760. }
  1761. @media (max-width: 768px) {
  1762. .part-form .el-col {
  1763. margin-bottom: 20px;
  1764. }
  1765. .form-section {
  1766. margin-bottom: 35px;
  1767. }
  1768. .part-form .el-form-item__label {
  1769. line-height: 28px;
  1770. height: 28px;
  1771. }
  1772. }
  1773. </style>