index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. <template>
  2. <div class="mainContentBox">
  3. <avue-crud
  4. ref="crudRef"
  5. v-model:search="search"
  6. v-model="form"
  7. :data="data"
  8. :option="option"
  9. v-model:page="page"
  10. @row-save="createRow"
  11. @row-update="updateRow"
  12. @row-del="deleteRow"
  13. @search-change="searchChange"
  14. @search-reset="resetChange"
  15. @size-change="dataList"
  16. @current-change="dataList"
  17. @selection-change="selectionChange"
  18. >
  19. <template #menu-left="{ size }">
  20. <el-button
  21. type="primary"
  22. icon="el-icon-plus"
  23. :size="size"
  24. @click="openDialog(0,null)"
  25. >新增</el-button>
  26. <el-button
  27. :disabled="toDeleteIds.length < 1"
  28. type="danger"
  29. icon="el-icon-delete"
  30. :size="size"
  31. @click="multipleDelete"
  32. >删除</el-button
  33. >
  34. </template>
  35. <template #menu="{size,row,index}">
  36. <el-button
  37. type="info"
  38. link
  39. size="small"
  40. @click="openDialog(1,row)"
  41. ><i-ep-edit />查看</el-button>
  42. <el-button
  43. type="primary"
  44. link
  45. size="small"
  46. @click="openDialog(2,row)"
  47. ><i-ep-edit />{{row.state === '0' ? '编辑' : '流程'}}</el-button>
  48. </template>
  49. </avue-crud>
  50. <el-dialog
  51. v-model="dialog.visible"
  52. :title="dialog.title"
  53. width="75%"
  54. @close="dialog.visible = false"
  55. >
  56. <template #header="{ close, titleId, titleClass }">
  57. <el-button v-if="dialogType === 1" type="primary" @click="printPage" size="small">打印</el-button>
  58. </template>
  59. <div class="card-container" >
  60. <el-card style="width: 70%" shadow="always">
  61. <div ref="toPrintRef">
  62. <el-row style="text-align: center;">
  63. <el-col :span="24"><el-text tag="b">零、部(组)件领用单</el-text></el-col>
  64. </el-row>
  65. <el-row>
  66. <el-col :span="14" ></el-col>
  67. <el-col :span="5" ><el-text tag="p" v-if="form.applyCode">{{form.applyCode}}</el-text></el-col>
  68. <el-col :span="5"></el-col>
  69. </el-row>
  70. <el-row style="width: 100%;height: 30px;"></el-row>
  71. <el-row>
  72. <el-col :span="2" ><el-text tag="p">领用单位:</el-text></el-col>
  73. <el-col :span="6" ><el-text tag="p" >{{form.applyOrg}}</el-text></el-col>
  74. <el-col :span="2" ><el-text tag="p">发件单位: </el-text></el-col>
  75. <el-col :span="6" ><el-text tag="p" >{{form.sendOrg}} </el-text></el-col>
  76. <el-col :span="2" ><el-text tag="p">工单编号:</el-text></el-col>
  77. <el-col :span="6">
  78. <el-text tag="p" v-if="dialogType === 1 || form.state > 0">{{form.workOrderCode}}</el-text>
  79. <el-select
  80. v-else
  81. size="small"
  82. v-model="form.workOrderCode"
  83. placeholder="请选择工单单号"
  84. clearable
  85. filterable
  86. @change="changeOrder"
  87. >
  88. <el-option
  89. v-for="option in orderList"
  90. :key="option.workOrderCode"
  91. :label="option.workOrderCode"
  92. :value="option.workOrderCode"
  93. />
  94. </el-select>
  95. </el-col>
  96. </el-row>
  97. <el-table class="print-table"
  98. v-loading="loading"
  99. :data="tableDataList"
  100. border
  101. >
  102. <el-table-column label="序号" type="index" width="60"/>
  103. <el-table-column label="工作令号" prop="workCode">
  104. <template v-slot="{row}">
  105. <el-text v-if="dialogType === 1 || form.state > 0">{{row.workCode}}</el-text>
  106. <el-input v-else v-model="row.workCode"/>
  107. </template>
  108. </el-table-column>
  109. <el-table-column label="零、部(组)件图号" prop="materialCode" />
  110. <el-table-column label="名称" prop="materialName" />
  111. <el-table-column label="数量" align="num">
  112. <template v-slot="{row}">
  113. <el-text v-if="dialogType === 1 || form.state > 0">{{row.num}}</el-text>
  114. <el-input v-else v-model="row.num" type="number"/>
  115. </template>
  116. </el-table-column>
  117. <el-table-column label="实际接收" align="receiveNum" v-if="form.state === '6' || form.state === '8'">
  118. <template v-slot="{row}">
  119. <el-text>{{row.receiveNum}}</el-text>
  120. </template>
  121. </el-table-column>
  122. <el-table-column label="备注" align="remark">
  123. <template v-slot="{row}">
  124. <el-text v-if="dialogType === 1 || form.state > 0">{{row.remark}}</el-text>
  125. <el-input v-else v-model="row.remark"/>
  126. </template>
  127. </el-table-column>
  128. <el-table-column label="操作" align="remark" v-if="form.state === '0'">
  129. <template v-slot="{row,index}">
  130. <el-button type="danger" @click="minusItem(row)" icon="el-icon-minus" style="margin-left:15px;width:25px;height:25px;" circle />
  131. </template>
  132. </el-table-column>
  133. </el-table>
  134. <el-row>
  135. <el-col :span="2" ><el-text tag="p">领用人:</el-text></el-col>
  136. <el-col :span="4" ><el-text tag="p" >{{form.applyUser}}</el-text></el-col>
  137. <el-col :span="2" ><el-text tag="p">审核: </el-text></el-col>
  138. <el-col :span="4" ><el-text tag="p" >{{form.auditUser}} </el-text></el-col>
  139. <el-col :span="2" ><el-text tag="p">会签:</el-text></el-col>
  140. <el-col :span="4" ><el-text tag="p" >{{form.countersignUser}}</el-text></el-col>
  141. <el-col :span="2" ><el-text tag="p">批准:</el-text></el-col>
  142. <el-col :span="4" ><el-text tag="p" >{{form.approveUser}}</el-text></el-col>
  143. </el-row>
  144. </div>
  145. </el-card>
  146. <el-card style="width: 28%" shadow="always">
  147. <template #header>
  148. <div class="card-header">
  149. <span>领用流程</span>
  150. </div>
  151. <el-timeline style="max-width: 500px;">
  152. <el-timeline-item center type="success" placement="top">
  153. <el-card>
  154. <h4>申请</h4>
  155. <el-form ref="maintenanceInfoForm2" size="small" :model="form" label-width="auto" style="max-width: 400px">
  156. <el-form-item label="领用人员" prop="auditUser">
  157. <el-text tag="p" v-if="dialogType === 1 || form.state > 0">{{form.applyUser}}</el-text>
  158. <el-select
  159. v-else
  160. size="small"
  161. filterable
  162. v-model="form.applyUser"
  163. placeholder="请选择领用人员"
  164. clearable>
  165. <el-option
  166. v-for="option in userList"
  167. :key="option.userName"
  168. :label="option.nickName"
  169. :value="option.userName" />
  170. </el-select>
  171. </el-form-item>
  172. <el-form-item label="审核人员" v-if="form.state === '0'">
  173. <el-text tag="p" v-if="dialogType === 1 || form.state > 0">{{form.auditUser}}</el-text>
  174. <el-select
  175. v-else
  176. size="small"
  177. filterable
  178. v-model="form.auditUser"
  179. placeholder="请选择审核人员"
  180. clearable>
  181. <el-option
  182. v-for="option in userList"
  183. :key="option.userName"
  184. :label="option.nickName"
  185. :value="option.userName" />
  186. </el-select>
  187. </el-form-item>
  188. <el-form-item label="申请时间" v-if="form.state > 0">
  189. <el-text tag="p">{{form.created}}</el-text>
  190. </el-form-item>
  191. <el-form-item style="margin-left: 28%" v-if="dialogType !==1">
  192. <el-button type="primary" @click="saveForm(1)" v-if="form.state === '0'">申 请</el-button>
  193. <el-button type="success" @click="saveForm(0)" v-if="form.state === '0'">保 存</el-button>
  194. </el-form-item>
  195. </el-form>
  196. </el-card>
  197. </el-timeline-item>
  198. <el-timeline-item center placement="top" :type="form.state > 1 ? 'success' : 'primary'">
  199. <el-card>
  200. <h4>审核</h4>
  201. <el-form v-if="form.state >= 1" size="small" :model="form" label-width="auto" style="max-width: 400px">
  202. <el-form-item label="审核人员" prop="auditUser">
  203. <el-text tag="p">{{form.auditUser}}</el-text>
  204. </el-form-item>
  205. <el-form-item label="处理结果">
  206. <el-text tag="p" v-if="dialogType === 1 || form.state !== '1'">{{form.state === '1' ? '待审核' : form.auditState === 0 ? "通过" : "未通过"}}</el-text>
  207. <el-text tag="p" v-else-if="form.auditUser !== username">{{form.auditState ? form.auditState === 0 ? "通过" : "未通过" : "待审核"}}</el-text>
  208. <el-radio-group v-else v-model="form.auditState">
  209. <el-radio :value=0>通过</el-radio>
  210. <el-radio :value=1>不通过</el-radio>
  211. </el-radio-group>
  212. </el-form-item>
  213. <el-form-item label="会签人员" v-if="dialogType !== 1 && form.state === '1' && form.auditUser === username">
  214. <el-select
  215. size="small"
  216. filterable
  217. multiple
  218. v-model="form.countersignUsers"
  219. placeholder="请选择会签人员"
  220. clearable>
  221. <el-option
  222. v-for="option in userList"
  223. :key="option.userName"
  224. :label="option.nickName"
  225. :value="option.userName" />
  226. </el-select>
  227. </el-form-item>
  228. <el-form-item label="审核时间" v-if="form.audit && form.audit.time">
  229. <el-text tag="p" >{{form.audit.time}}</el-text>
  230. </el-form-item>
  231. <el-form-item style="margin-left: 35%">
  232. <el-button type="primary" @click="saveForm(2)" v-if="dialogType !== 1 && form.state === '1' && form.auditUser === username">审 核</el-button>
  233. </el-form-item>
  234. </el-form>
  235. </el-card>
  236. </el-timeline-item>
  237. <el-timeline-item center placement="top" :type="form.state > 3 ? 'success' : 'primary'">
  238. <el-card>
  239. <h4>会签</h4>
  240. <el-form v-if="form.state >= 3" size="small" :model="form" label-width="auto" style="max-width: 400px">
  241. <el-form-item v-for="item of form.countersign" label="会签人员:">
  242. <el-text tag="p" >{{item.user}}--</el-text>
  243. <el-text tag="p" v-if="dialogType === 1 || item.user !== username">{{item.state === -1 ? '未审核' : item.state === 0 ? '通过' : '未通过'}}</el-text>
  244. <el-text tag="p" v-else-if="item.state !== -1 && item.user === username">{{item.state === 0 ? '通过' : '未通过'}}</el-text>
  245. <el-radio-group v-model="form.countersignState" v-if="dialogType !== 1 && item.state === -1 && item.user === username">
  246. <el-radio :value=0>通过</el-radio>
  247. <el-radio :value=1>不通过</el-radio>
  248. </el-radio-group>
  249. </el-form-item>
  250. <el-form-item label="批准人员" v-if="dialogType !== 1 && form.countersignOk && form.state === '3'">
  251. <el-select
  252. size="small"
  253. v-model="form.approveUser"
  254. placeholder="请选择批准人员"
  255. clearable >
  256. <el-option
  257. v-for="option in userList"
  258. :key="option.userName"
  259. :label="option.nickName"
  260. :value="option.userName" />
  261. </el-select>
  262. </el-form-item>
  263. <el-form-item label="通过时间" v-if="form.countersignInfo && form.countersignInfo.time">
  264. <el-text tag="p" >{{form.countersignInfo.time}}</el-text>
  265. </el-form-item>
  266. <el-form-item style="margin-left: 35%">
  267. <el-button type="primary" v-if="dialogType !== 1 && form.state === '3' && form.countersignUser.includes(username) && form.countersignBtn" @click="saveForm(3)">审 核</el-button>
  268. </el-form-item>
  269. </el-form>
  270. </el-card>
  271. </el-timeline-item>
  272. <el-timeline-item center placement="top" :type="form.state > 5 ? 'success' : 'primary'">
  273. <el-card>
  274. <h4>批准</h4>
  275. <el-form v-if="form.state >= 5" size="small" :model="form" label-width="auto" style="max-width: 400px">
  276. <el-form-item label="审批人" v-if="form.state > 5">
  277. <el-text tag="p">{{form.approve.user}}</el-text>
  278. </el-form-item>
  279. <el-form-item label="审批结果">
  280. <el-text tag="p" v-if="dialogType === 1 || form.state === '6' || form.state === '7'">{{form.state === '5' ? '待审批' : form.state === '6' ? '通过' : '未通过'}}</el-text>
  281. <el-text tag="p" v-else-if="form.approveUser !== username">待审批</el-text>
  282. <el-radio-group v-else v-model="form.approveState">
  283. <el-radio :value=0>通过</el-radio>
  284. <el-radio :value=1>不通过</el-radio>
  285. </el-radio-group>
  286. </el-form-item>
  287. <el-form-item label="审批时间" v-if="form.state > 5">
  288. <el-text tag="p">{{form.approve.time}}</el-text>
  289. </el-form-item>
  290. <el-form-item style="margin-left: 35%">
  291. <el-button type="primary" @click="saveForm(4)" v-if="dialogType !== 1 && form.state === '5' && form.approveUser === username">审 核</el-button>
  292. </el-form-item>
  293. </el-form>
  294. </el-card>
  295. </el-timeline-item>
  296. </el-timeline>
  297. </template>
  298. </el-card>
  299. </div>
  300. </el-dialog>
  301. </div>
  302. </template>
  303. <script setup>
  304. import { useUserStoreHook } from "@/store/index";
  305. import { ref, getCurrentInstance } from "vue";
  306. import { html2CanvasPrint } from "@/utils/common";
  307. import { useCrud } from "@/hooks/userCrud";
  308. import dictDataUtil from "@/common/configs/dictDataUtil";
  309. import {queryApplyInfoDetails,queryWorkOrderList,saveApplyInfoDetails,auditApplyInfoDetails} from "@/api/order"
  310. import {getUserList} from "@/api/system/user"
  311. import { useCommonStoreHook } from "@/store";
  312. const { isShowTable, tableType } = toRefs(useCommonStoreHook());
  313. const test = () => {
  314. isShowTable.value = true;
  315. tableType.value = tableType.value == 1 ? 2 : 1;
  316. };
  317. // 1.定义ref
  318. const toPrintRef = ref(null);
  319. // 传入一个url,后面不带/
  320. const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
  321. useCrud({
  322. src: "/api/v1/plan/requisition",
  323. });
  324. const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } = Methords; //增删改查
  325. const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
  326. const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
  327. const { username } = useUserStoreHook().user;
  328. const minusItem =(row)=>{
  329. tableDataList.value = tableDataList.value.filter(item=>item.id !== row.id)
  330. }
  331. const changeOrder =(val)=>{
  332. queryApplyInfoDetails({workOrderCode: val}).then((data)=>{
  333. tableDataList.value = data.data
  334. })
  335. }
  336. const saveForm = (type) =>{
  337. let state = type;
  338. let step = null;
  339. let nextUsers = ""
  340. if(type === 1 || type === 0){
  341. if(tableDataList.value.length === 0){
  342. ElMessage.error("当前没有申请的物料信息")
  343. return;
  344. }
  345. for(let item of tableDataList.value){
  346. if(!item.workCode){
  347. ElMessage.error("工作令号不能为空")
  348. return;
  349. }
  350. if(!item.num || item.num <=0){
  351. ElMessage.error("物料数量不正确")
  352. return;
  353. }
  354. }
  355. if(!form.value.applyUser){
  356. ElMessage.error("领用人员不能为空")
  357. return;
  358. }
  359. if(!form.value.auditUser){
  360. ElMessage.error("审核人员不能为空")
  361. return;
  362. }
  363. const params = {...form.value,'state': state,details: tableDataList.value}
  364. saveApplyInfoDetails(params).then((data)=>{
  365. if(data.code === '200'){
  366. ElMessage.success(data.msg)
  367. dialog.visible = false
  368. dataList()
  369. }else{
  370. ElMessage.error(data.msg)
  371. }
  372. })
  373. return;
  374. }
  375. step = "audit";
  376. if(type === 2){
  377. if(form.value.auditState != undefined){
  378. if(form.value.auditState === 0 && form.value.countersignUsers.length === 0){
  379. ElMessage.error("会签人员不能为空")
  380. return;
  381. }
  382. }else{
  383. if(!form.value.auditState){
  384. ElMessage.error("请选择处理结果")
  385. return;
  386. }
  387. }
  388. nextUsers = form.value.countersignUsers.join(",")
  389. state = form.value.auditState
  390. }
  391. if(type === 3){
  392. step = "countersign";
  393. if(!form.value.approveUser && form.value.countersignOk){
  394. ElMessage.error("请选择审批人员")
  395. return;
  396. }
  397. if(form.value.countersignState === undefined){
  398. ElMessage.error("请选择处理结果")
  399. return;
  400. }
  401. nextUsers = form.value.approveUser
  402. state = form.value.countersignState
  403. }
  404. if(type === 4){
  405. step = "approve";
  406. if(form.value.approveState === undefined){
  407. ElMessage.error("请选择处理结果")
  408. return;
  409. }
  410. state = form.value.approveState
  411. }
  412. const params = {id: form.value.id,'state': state,currentStep: step,nextUser: nextUsers}
  413. auditApplyInfoDetails(params).then((data)=>{
  414. if(data.code === '200'){
  415. ElMessage.success(data.msg)
  416. dialog.visible = false
  417. dataList()
  418. }else{
  419. ElMessage.error(data.msg)
  420. }
  421. })
  422. }
  423. const loading = ref(false)
  424. const crudRef = ref(null); //crudRef.value 获取avue-crud对象
  425. const userList = ref([])
  426. const orderList = ref([])
  427. const dialogType = ref(false)
  428. const dialog = reactive({
  429. title: "领用单",
  430. visible: false,
  431. });
  432. const tableDataList = ref([])
  433. const openDialog = (type,row)=>{
  434. dialogType.value = type
  435. tableDataList.value = []
  436. form.value = {}
  437. form.value.sendOrg = "周转库";
  438. form.value.applyOrg = "制造中心"
  439. form.value.state = "0"
  440. if(type !== 0){
  441. queryApplyInfoDetails({applyCode: row.applyCode}).then((data)=>{
  442. tableDataList.value = data.data
  443. })
  444. form.value = row
  445. }
  446. form.value.countersign = []
  447. if(row && row.flowInfo){
  448. let json = JSON.parse(row.flowInfo)
  449. let auditInfo = json.audit
  450. if(auditInfo){
  451. form.value.audit =auditInfo.info
  452. form.value.auditState = form.value.audit.state
  453. }
  454. if(row.countersignUser){
  455. form.value.countersignUsers = row.countersignUser.split(",")
  456. }
  457. form.value.countersignBtn = false
  458. if(json.countersign){
  459. form.value.countersign = json.countersign.list
  460. form.value.countersignInfo = json.countersign.info
  461. //当断当前是否最后一个
  462. let isOk = true
  463. for(let obj of form.value.countersign){
  464. if(obj.state === -1 && obj.user === username){
  465. form.value.countersignBtn = true
  466. }
  467. if(obj.user !== username && obj.state === -1){
  468. isOk = false
  469. }
  470. }
  471. form.value.countersignOk = isOk;
  472. }
  473. if(json.approve){
  474. form.value.approve = json.approve.info
  475. }
  476. form.value.approveUser = row.approveUser
  477. }
  478. dialog.visible = true
  479. getUserList({}).then((data)=>{
  480. userList.value = data.data
  481. })
  482. }
  483. const printPage = ()=>{
  484. html2CanvasPrint(toPrintRef.value);
  485. }
  486. // 设置表格列或者其他自定义的option
  487. option.value = Object.assign(option.value, {
  488. delBtn: false,
  489. addBtn: false,
  490. editBtn: false,
  491. viewBtn: false,
  492. selection: true,
  493. column: [
  494. {
  495. label: "领用单号",
  496. prop: "applyCode",
  497. search: true,
  498. width: 150,
  499. overHidden: true,
  500. },
  501. {
  502. label: "工单单号",
  503. prop: "workOrderCode",
  504. search: true,
  505. width: 150,
  506. overHidden: true,
  507. },
  508. {
  509. label: "计划单号",
  510. prop: "orderCode",
  511. search: true,
  512. width: 150,
  513. overHidden: true,
  514. },
  515. {
  516. label: "领用单位",
  517. prop: "applyOrg",
  518. width: 150,
  519. overHidden: true,
  520. },
  521. {
  522. label: "发件单位",
  523. prop: "sendOrg",
  524. width: 150,
  525. overHidden: true,
  526. },
  527. {
  528. label: "领用人员",
  529. prop: "applyUser",
  530. width: 150,
  531. overHidden: true,
  532. search: true,
  533. },
  534. {
  535. label: "审核人员",
  536. prop: "auditUser",
  537. width: 150,
  538. overHidden: true,
  539. },
  540. {
  541. label: "会签人员",
  542. width: 150,
  543. overHidden: true,
  544. prop: "countersignUser",
  545. },
  546. {
  547. label: "审批人员",
  548. width: 150,
  549. overHidden: true,
  550. prop: "approveUser",
  551. },
  552. {
  553. label: "状态",
  554. prop: "state",
  555. width: 150,
  556. type: 'select',
  557. dicUrl: dictDataUtil.request_url + dictDataUtil.TYPE_CODE.requisition_state,
  558. props: {
  559. label: "dictLabel", // 下拉菜单显示的字段
  560. value: "dictValue" // 下拉菜单值的字
  561. },
  562. },
  563. {
  564. label: "创建时间",
  565. prop: "created",
  566. width: 160,
  567. display: false
  568. },
  569. ],
  570. });
  571. onMounted(() => {
  572. queryWorkOrderList({}).then((data)=>{
  573. if(!data.data){
  574. ElMessage.warning("请维护物料BOM")
  575. }
  576. orderList.value = data.data
  577. })
  578. // console.log("crudRef", crudRef)
  579. dataList();
  580. });
  581. </script>
  582. <style scoped>
  583. :deep(.card-container .el-form-item) {
  584. display: flex;
  585. justify-content: center;
  586. align-items: center;
  587. height: 15px; /* 根据需要调整高度 */
  588. }
  589. :deep(.el-timeline-item){
  590. padding-bottom: 0px;
  591. position: relative;
  592. }
  593. .card-container {
  594. display: flex;
  595. justify-content: space-around;
  596. }
  597. </style>