自主产品,供应链食堂系统。将两个端拆开了。
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.

666 lines
18 KiB

5 years ago
  1. <template>
  2. <view>
  3. <view class="box">
  4. <view class="title">报价清单</view>
  5. <view class="lf-font-24 lf-color-gray lf-m-t-5">请在以下物资信息表内填写报价</view>
  6. </view>
  7. <!-- 修饰条 -->
  8. <self-line></self-line>
  9. <view class="box lf-row-between relation">
  10. <view>
  11. <text class="title">关联食堂</text>
  12. <text class="lf-font-24 lf-color-555 lf-m-l-10">(多选)</text>
  13. </view>
  14. <view class="lf-font-24 lf-color-gray lf-text-right lf-row-center" style="width: 370rpx; justify-content: flex-end;" @click="switchRelation">
  15. <view class="lf-line-1">{{ selectName }}</view>
  16. <u-icon name="arrow-right" class="lf-text-vertical"></u-icon>
  17. </view>
  18. <view class="mask" :style="{top: node_top +'px'}" v-if="is_show" @click="is_show = false">
  19. <view class="list">
  20. <view class="lf-row-between item" v-for="(item, index) in relation_list" :key="index" @click.stop="selectItem(index)">
  21. <view>{{ item.canteen_name }}</view>
  22. <u-icon name="checkmark-circle" color="#1833F2" size="40" v-if="item.checked"></u-icon>
  23. </view>
  24. </view>
  25. </view>
  26. </view>
  27. <self-line></self-line>
  28. <!-- 报价时间 -->
  29. <view class="lf-row-between lf-p-30 lf-p-l-32 lf-p-r-32 lf-font-28">
  30. <view class="lf-color-black">报价生效时间</view>
  31. <picker mode="date" :value="deadline_start" @change="pickerChange($event, 'deadline_start')">
  32. <view class="lf-color-555 lf-text-right" style="width: 400rpx;">{{ deadline_start || '请选择...' }}</view>
  33. </picker>
  34. </view>
  35. <view class="lf-row-between lf-p-30 lf-p-l-32 lf-p-r-32 lf-font-28">
  36. <view class="lf-color-black">报价失效时间</view>
  37. <picker mode="date" :value="deadline_end" @change="pickerChange($event, 'deadline_end')">
  38. <view class="lf-color-555 lf-text-right" style="width: 400rpx;">{{ deadline_end || '请选择...' }}</view>
  39. </picker>
  40. </view>
  41. <self-line></self-line>
  42. <!-- 物料table -->
  43. <view class="box">
  44. <view class="lf-m-b-20 lf-row-between">
  45. <view class="lf-font-32 lf-color-black lf-font-bold">报价明细</view>
  46. <view class="lf-flex search-self">
  47. <u-icon name="search" class="search-icon"></u-icon>
  48. <input placeholder="搜索物资" confirm-type="search" @focus="hideIcon()" class="lf-m-l-10 lf-font-28" :value="searchValue" @input="inputChange" @confirm="inputConfirm" />
  49. </view>
  50. </view>
  51. <wyb-table :first-line-fixed="true"
  52. contentBgColor="#eef6fe"
  53. :headers="headers"
  54. :contents="contents"
  55. :scrollToInput="true"
  56. :loading="table_loading"
  57. :searchKey="searchValue"
  58. @onInputChange="onInputChange"
  59. @onButtonClick="onButtonClick"
  60. width="100%" height="80vh"></wyb-table>
  61. </view>
  62. <view style="height: 140rpx;"></view>
  63. <!-- 操作按钮 -->
  64. <view class="fixed-bottom">
  65. <button class="btn btn1" :class="{'lf-btn-disabled': button_click}" @click="save(0)">临时保存</button>
  66. <button class="btn btn2" :class="{'lf-btn-disabled': button_click}" @click="save(1)">直接报价</button>
  67. </view>
  68. </view>
  69. </template>
  70. <script>
  71. import wybTable from '@/components/wyb-table/wyb-table';
  72. let app = getApp();
  73. let timer = null;
  74. export default {
  75. components: {
  76. wybTable
  77. },
  78. data(){
  79. return {
  80. show_icon: true,
  81. headers: [{
  82. label: '物资名称',
  83. key: 'name',
  84. search: true
  85. },{
  86. label: '规格',
  87. key: 'spec'
  88. },{
  89. label: '单位',
  90. key: 'unit'
  91. },{
  92. label: '分类',
  93. key: 'category'
  94. },{
  95. label: '品牌',
  96. key: 'brand'
  97. },{
  98. label: '品级',
  99. key: 'quality_level'
  100. },{
  101. label: '编号',
  102. key: 'number'
  103. },{
  104. label: '起购数',
  105. key: 'purchase_limit'
  106. },{
  107. label: '含税价',
  108. key: 'tax_price'
  109. },{
  110. label: '不含税价',
  111. key: 'non_tax_price'
  112. },{
  113. label: '操作',
  114. key: 'operation'
  115. }],
  116. contents: [],
  117. is_show: false,
  118. relation_list: [], // 关联食堂列表
  119. node_top: 0,
  120. code: '', // 订单号,批次号,如果有
  121. type: 0,
  122. deadline_start: '',
  123. deadline_end: '',
  124. table_loading: true,
  125. searchValue: '', // 搜索内容
  126. button_click: false,
  127. selected_canteens: []
  128. }
  129. },
  130. computed: {
  131. selectName(){
  132. let arr = [];
  133. this.relation_list.map(item => {
  134. if(item.checked){
  135. arr.push(item.canteen_name);
  136. }
  137. });
  138. let str = '请选择...';
  139. if(arr.length > 0){
  140. str = arr.join(',');
  141. }
  142. return str;
  143. }
  144. },
  145. onLoad(options){
  146. this.code = options.code || '';
  147. this.type = options.type || 0;
  148. this.getOfferList();
  149. if(options.type == 1){
  150. // 编辑,不可更换食堂
  151. this.materialListByOrder();
  152. }else if(options.type == 2){
  153. // 复用订单号
  154. this.materialListByOrder();
  155. }else if(options.type == 3){
  156. // 复用批次号
  157. this.materialListByBatch();
  158. }else{
  159. // 单纯发起报价
  160. this.getMaterialList();
  161. }
  162. },
  163. onReady(){
  164. let that = this;
  165. let info = uni.createSelectorQuery().select(".relation");
  166.     info.boundingClientRect(function(data) {
  167. let num = app.globalData.customBarH;
  168. // #ifdef MP-WEIXIN
  169. num -= 60;
  170. // #endif
  171. num += data.height;
  172. num += data.top;
  173. that.node_top = num;
  174.    }).exec()
  175. },
  176. onPageScroll(){
  177. if(this.is_show){
  178. this.is_show = false;
  179. }
  180. },
  181. methods: {
  182. // 获取订单列表(取出食堂id)
  183. getOfferList(){
  184. this.$http(this.API.API_SUPPLIER_QUOTATIONORDERLIST, {
  185. state: 1,
  186. page: 1,
  187. page_size: 10
  188. }).then(res => {
  189. let list = res.data?.list?.data || [];
  190. // 数组对象去重
  191. list = this.$shared.deWeightFour(list, 'canteen_id');
  192. let selected_canteens = [];
  193. list.map(item => {
  194. if(item.state == '待审核'){
  195. selected_canteens.push({
  196. id: item.canteen_id,
  197. q_sn: item.q_sn
  198. })
  199. }
  200. })
  201. this.selected_canteens = selected_canteens;
  202. })
  203. },
  204. hideIcon() {
  205. if(this.searchValue != '') {
  206. this.show_icon = false;
  207. }
  208. },
  209. // 搜索input值被改变
  210. inputChange(event){
  211. if(timer){
  212. clearTimeout(timer);
  213. timer = null;
  214. }
  215. timer = setTimeout(() => {
  216. this.searchValue = event.detail.value;
  217. }, 1000);
  218. if(event.detail.value == '') {
  219. this.show_icon = true;
  220. }else {
  221. this.show_icon = false;
  222. }
  223. },
  224. // 搜索按下回车
  225. inputConfirm(event){
  226. this.searchValue = event.detail.value;
  227. },
  228. // 日期选择器值被改变
  229. pickerChange(event, current_name){
  230. if(current_name == 'deadline_start') {
  231. // PS 获取30天后日期
  232. var date1 = new Date(event.detail.value);
  233. var date2 = new Date(date1);
  234. date2.setDate(date1.getDate() + 30);
  235. var nowTime = new Date(new Date().toLocaleDateString()).getTime();
  236. let oldTime = new Date(new Date(event.detail.value).toLocaleDateString()).getTime();
  237. if(nowTime>oldTime) {
  238. this.$msg('请选择今天或未来的时间')
  239. return
  240. }else {
  241. this[current_name] = event.detail.value;
  242. this.deadline_end = this.$shared.recordTime(date2, '-', 'date')
  243. }
  244. }else {
  245. var nowTime = new Date(new Date().toLocaleDateString()).getTime();
  246. let oldTime = new Date(new Date(event.detail.value).toLocaleDateString()).getTime();
  247. if(nowTime>oldTime) {
  248. this.$msg('请选择今天之后的时间')
  249. return
  250. }else {
  251. if(this.deadline_start >= event.detail.value) {
  252. this.$msg('失效时间不能小于报价生效时间')
  253. return
  254. }else {
  255. this[current_name] = event.detail.value;
  256. }
  257. }
  258. }
  259. },
  260. // 获取物资列表
  261. getMaterialList(){
  262. this.$http(this.API.API_SUPPLIER_MATERIALLIST).then(res => {
  263. let list = res.data.spec || [];
  264. let contents = list.map(item => {
  265. return {
  266. name: item?.material?.m_name || '',
  267. material_id: item?.material?.id || 0,
  268. spec: item.name || '',
  269. spec_id: item.id,
  270. brand: item?.material?.brand || '',
  271. quality_level: item?.material?.quality_level || '',
  272. number: item?.material?.m_sn || '',
  273. purchase_limit: {edit: true, value: 1},
  274. tax_price: {edit: true, value: ''},
  275. non_tax_price: {edit: true, value: ''},
  276. operation: {button: true, key: 'delete', value: '删除'},
  277. unit: item?.material?.unit?.unit_name || '',
  278. category: item?.material?.category?.m_cate_name || ''
  279. }
  280. })
  281. this.contents = contents;
  282. this.table_loading = false;
  283. this.getCanteenList();
  284. })
  285. },
  286. // 复用报价订单号 & 编辑共用
  287. materialListByOrder(){
  288. this.$http(this.API.API_SUPPLIER_QUOTATIONREUSEBYORDER, {
  289. q_sn: this.code
  290. }).then(res => {
  291. let list = res.data.order || [];
  292. let canteen = res.data.canteen || [];
  293. // 处理表格显示
  294. let contents = list.map(item => {
  295. let obj = {
  296. name: item?.material?.m_name || '',
  297. material_id: item?.material?.id || 0,
  298. spec: item.name || '',
  299. spec_id: item.id,
  300. brand: item?.material?.brand || '',
  301. quality_level: item?.material?.quality_level || '',
  302. number: item?.material?.m_sn || '',
  303. purchase_limit: {edit: true, value: item?.quotation_item?.purchase_limit || ''},
  304. tax_price: {edit: true, value: item?.quotation_item?.tax_price || ''},
  305. non_tax_price: {edit: true, value: item?.quotation_item?.non_tax_price || ''},
  306. quotation_id: item?.quotation_item?.id || 0,
  307. operation: {button: true, key: 'delete', value: '删除'},
  308. unit: item?.material?.unit?.unit_name || '',
  309. category: item?.material?.category?.m_cate_name || ''
  310. }
  311. if(item?.material?.state && item?.material?.state != '启用'){
  312. obj.disabled = true;
  313. }
  314. return obj;
  315. })
  316. this.contents = contents;
  317. this.table_loading = false;
  318. // 处理报价生效、失效时间
  319. let deadline_start = '';
  320. let deadline_end = '';
  321. if(list[0] && list[0]?.quotation_item?.quotation){
  322. let quotation = list[0]?.quotation_item?.quotation || {};
  323. if(quotation.deadline_start){
  324. deadline_start = quotation.deadline_start.split(' ')[0];
  325. }
  326. if(quotation.deadline){
  327. deadline_end = quotation.deadline.split(' ')[0];
  328. }
  329. }
  330. this.deadline_start = deadline_start;
  331. this.deadline_end = deadline_end;
  332. this.getCanteenList(canteen);
  333. })
  334. },
  335. // 复用批次号
  336. materialListByBatch(){
  337. this.$http(this.API.API_SUPPLIER_QUOTATIONREUSEBYBATCH, {
  338. batch_sn: this.code
  339. }).then(res => {
  340. console.log("materialListByBatch", res);
  341. let list = res.data.order || [];
  342. let canteen = res.data.canteen || [];
  343. // 处理表格显示
  344. let contents = list.map(item => {
  345. return {
  346. name: item?.material?.m_name || '',
  347. material_id: item?.material?.id || 0,
  348. spec: item.name || '',
  349. spec_id: item.id,
  350. brand: item?.material?.brand || '',
  351. quality_level: item?.material?.quality_level || '',
  352. number: item?.material?.m_sn || '',
  353. purchase_limit: {edit: true, value: item?.quotation?.purchase_limit || ''},
  354. tax_price: {edit: true, value: item?.quotation?.tax_price || ''},
  355. non_tax_price: {edit: true, value: item?.quotation?.non_tax_price || ''}
  356. }
  357. })
  358. this.contents = contents;
  359. this.table_loading = false;
  360. // 处理报价生效、失效时间
  361. let deadline_start = '';
  362. let deadline_end = '';
  363. if(list[0] && list[0]?.quotation_item?.quotation){
  364. let quotation = list[0]?.quotation_item?.quotation || {};
  365. if(quotation.deadline_start){
  366. deadline_start = quotation.deadline_start.split(' ')[0];
  367. }
  368. if(quotation.deadline){
  369. deadline_end = quotation.deadline.split(' ')[0];
  370. }
  371. }
  372. this.deadline_start = deadline_start;
  373. this.deadline_end = deadline_end;
  374. this.getCanteenList(canteen);
  375. })
  376. },
  377. // 关联食堂列表
  378. getCanteenList(canteen = []){
  379. this.$http(this.API.API_SUPPLIER_CANTEENLIST).then(res => {
  380. let list = res.data.list.map(item => {
  381. item.checked = false;
  382. canteen.map(ct => {
  383. if(ct == item.id){
  384. item.checked = true;
  385. }
  386. })
  387. return item;
  388. })
  389. this.relation_list = list;
  390. })
  391. },
  392. // 监听表格被输入
  393. onInputChange(event){
  394. this.contents[event.contentIndex][event.key].value = event.detailValue;
  395. },
  396. // table操作按钮被点击
  397. onButtonClick(event){
  398. if(event.content.key == 'delete'){
  399. let contentIndex = event.contentIndex;
  400. let name = event?.lineData?.name || '';
  401. let spec = event?.lineData?.spec || '';
  402. uni.showModal({
  403. title: '温馨提示',
  404. content: `确定删除 ${name}-${spec} 吗?`,
  405. confirmColor: '#1833F2',
  406. success: result => {
  407. if(result.confirm){
  408. this.contents.splice(contentIndex, 1);
  409. }
  410. }
  411. })
  412. }
  413. },
  414. // 切换显示关联食堂modal
  415. switchRelation(){
  416. if(this.type == 1) return this.$msg('编辑不可更换关联食堂哦');
  417. this.is_show = !this.is_show;
  418. },
  419. // 选择食堂
  420. selectItem(index){
  421. this.relation_list[index].checked = !this.relation_list[index].checked;
  422. },
  423. // 报价订单编辑时保存
  424. editMaterial(_t){
  425. // 物资列表
  426. let that = this;
  427. let list = [];
  428. this.contents.map(item => {
  429. list.push({
  430. // id: item.quotation_id,
  431. m_id: item.material_id,
  432. m_spec_id: item.spec_id,
  433. tax_price: item.tax_price.value,
  434. non_tax_price: item.non_tax_price.value,
  435. purchase_limit: Number(item.purchase_limit.value) || 1
  436. })
  437. });
  438. // 已报价的食堂
  439. let already_offer;
  440. // 关联食堂
  441. this.relation_list.map(item => {
  442. if(item.checked){
  443. already_offer = this.selected_canteens.find(s_item => s_item.id == item.id);
  444. }
  445. })
  446. if(_t == 1 && typeof(already_offer) != 'undefined'){
  447. uni.showModal({
  448. title: '您当前已有相同食堂报价单审核中',
  449. content: `编号【${already_offer.q_sn}】,仍要发起,之前待审核报价单将会撤回`,
  450. success: result => {
  451. if(result.confirm){
  452. launchRequest();
  453. }else{
  454. this.button_click = false;
  455. }
  456. }
  457. })
  458. }else{
  459. launchRequest();
  460. }
  461. function launchRequest(){
  462. // 操作状态,是保存还是直接发起
  463. let state = ['待发起', '待审核'][_t];
  464. that.$http(that.API.API_SUPPLIER_QUOTATIONSAVE, {
  465. data: list,
  466. state: state,
  467. q_sn: that.code,
  468. start: that.deadline_start,
  469. end: that.deadline_end
  470. }).then(res => {
  471. that.$msg('操作成功').then(result => {
  472. that.$toBack();
  473. })
  474. }).catch(err => that.button_click = false)
  475. }
  476. },
  477. // 保存
  478. save(_t){
  479. let that = this;
  480. // 拦截按钮重复点击
  481. if(this.button_click){
  482. return;
  483. }
  484. this.button_click = true;
  485. // 拦截是编辑的情况
  486. if(this.type == 1){
  487. this.editMaterial(_t);
  488. return;
  489. }
  490. // 物资列表
  491. let list = [];
  492. this.contents.map(item => {
  493. if(item.tax_price.value && item.non_tax_price.value){
  494. list.push({
  495. m_id: item.material_id,
  496. m_spec_id: item.spec_id,
  497. tax_price: item.tax_price.value,
  498. non_tax_price: item.non_tax_price.value,
  499. purchase_limit: Number(item.purchase_limit.value) || 1
  500. })
  501. }
  502. });
  503. // 已报价的食堂
  504. let already_offer;
  505. // 关联食堂
  506. let canteen_ids = [];
  507. this.relation_list.map(item => {
  508. if(item.checked){
  509. canteen_ids.push(item.id);
  510. already_offer = this.selected_canteens.find(s_item => s_item.id == item.id);
  511. }
  512. })
  513. if(canteen_ids.length <= 0){
  514. this.button_click = false;
  515. return this.$msg('您未选择关联食堂哦')
  516. }
  517. if(!this.deadline_start){
  518. this.button_click = false;
  519. return this.$msg('您未选择报价生效时间哦')
  520. }
  521. if(!this.deadline_end){
  522. this.button_click = false;
  523. return this.$msg('您未选择报价失效时间哦')
  524. }
  525. if(list.length <= 0){
  526. this.button_click = false;
  527. return this.$msg('请补充完整物资报价信息')
  528. }
  529. if(_t == 1 && typeof(already_offer) != 'undefined'){
  530. uni.showModal({
  531. title: '您当前已有相同食堂报价单审核中',
  532. content: `编号【${already_offer.q_sn}】,仍要发起,之前待审核报价单将会撤回`,
  533. success: result => {
  534. if(result.confirm){
  535. launchRequest();
  536. }else{
  537. this.button_click = false;
  538. }
  539. }
  540. })
  541. }else{
  542. launchRequest();
  543. }
  544. function launchRequest(){
  545. // 操作状态,是保存还是直接发起
  546. let state = ['待发起', '待审核'][_t];
  547. that.$http(that.API.API_SUPPLIER_QUOTATIONAPPLY, {
  548. data: list,
  549. state: state,
  550. canteen_ids: canteen_ids,
  551. start: that.deadline_start,
  552. end: that.deadline_end
  553. }).then(res => {
  554. that.$msg(res.data).then(result => {
  555. that.$toBack();
  556. })
  557. }).catch(err => that.button_click = false)
  558. }
  559. }
  560. }
  561. }
  562. </script>
  563. <style>
  564. page{
  565. overflow-x: hidden;
  566. }
  567. </style>
  568. <style lang="scss" scoped="scoped">
  569. .search-icon {
  570. color: #777;
  571. }
  572. .search-self {
  573. background: #f2f2f2;
  574. padding: 10rpx 0 10rpx 20rpx;
  575. border-radius: 40rpx;
  576. font-size: 28rpx;
  577. }
  578. .search-self .uni-input-placeholder {
  579. margin-right: 500px;
  580. color: #777;
  581. font-size: 28rpx;
  582. }
  583. .lf-m-t-5{
  584. margin-top: 5rpx;
  585. }
  586. .box{
  587. padding: 30rpx 32rpx;
  588. width: 100%;
  589. height: max-content;
  590. box-sizing: border-box;
  591. }
  592. .title{
  593. color: #222222;
  594. font-size: 28rpx;
  595. font-weight: bold;
  596. }
  597. .fixed-bottom{
  598. position: fixed;
  599. bottom: 0rpx;
  600. left: 0rpx;
  601. z-index: 99;
  602. width: 750rpx;
  603. height: 98rpx;
  604. display: flex;
  605. justify-content: center;
  606. align-items: center;
  607. border-top: 1rpx solid #E5E5E5;
  608. background-color: #fff;
  609. .btn{
  610. width: 320rpx;
  611. height: 82rpx;
  612. border-radius: 41rpx;
  613. margin: 0;
  614. padding: 0;
  615. font-size: 32rpx;
  616. display: flex;
  617. justify-content: center;
  618. align-items: center;
  619. }
  620. .btn1{
  621. border: 2rpx solid #555555;
  622. opacity: .5;
  623. }
  624. .btn2{
  625. background: #1833F2;
  626. color: #FFFFFF;
  627. margin-left: 50rpx;
  628. }
  629. }
  630. .relation{
  631. position: relative;
  632. border-bottom: 1rpx solid #E5E5E5;
  633. }
  634. .mask{
  635. position: fixed;
  636. background-color: rgba(0,0,0,0.4);
  637. width: 100%;
  638. // top: 149px;
  639. bottom: 0;
  640. left: 0;
  641. z-index: 100;
  642. .list{
  643. min-height: max-content;
  644. max-height: 500rpx;
  645. overflow: scroll;
  646. background-color: #FFFFFF;
  647. width: 100%;
  648. .item{
  649. height: 92rpx;
  650. padding: 0 32rpx;
  651. border-bottom: 1rpx solid #E5E5E5;
  652. color: #222222;
  653. font-size: 28rpx;
  654. }
  655. }
  656. }
  657. </style>