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

532 lines
15 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. <input placeholder="搜索物资" confirm-type="search" :value="searchValue" @input="inputChange" @confirm="inputConfirm" style="background: pink;" />
  47. </view>
  48. <wyb-table :first-line-fixed="true"
  49. contentBgColor="#eef6fe"
  50. :headers="headers"
  51. :contents="contents"
  52. :scrollToInput="true"
  53. :loading="table_loading"
  54. :searchKey="searchValue"
  55. @onInputChange="onInputChange"
  56. @onButtonClick="onButtonClick"
  57. width="100%" height="80vh"></wyb-table>
  58. </view>
  59. <view style="height: 140rpx;"></view>
  60. <!-- 操作按钮 -->
  61. <view class="fixed-bottom">
  62. <button class="btn btn1" @click="save(0)">临时保存</button>
  63. <button class="btn btn2" @click="save(1)">直接报价</button>
  64. </view>
  65. </view>
  66. </template>
  67. <script>
  68. import wybTable from '@/components/wyb-table/wyb-table';
  69. let app = getApp();
  70. let timer = null;
  71. export default {
  72. components: {
  73. wybTable
  74. },
  75. data(){
  76. return {
  77. headers: [{
  78. label: '物资名称',
  79. key: 'name',
  80. search: true
  81. },{
  82. label: '规格',
  83. key: 'spec'
  84. },{
  85. label: '单位',
  86. key: 'unit'
  87. },{
  88. label: '分类',
  89. key: 'category'
  90. },{
  91. label: '品牌',
  92. key: 'brand'
  93. },{
  94. label: '品级',
  95. key: 'quality_level'
  96. },{
  97. label: '编号',
  98. key: 'number'
  99. },{
  100. label: '起购数',
  101. key: 'purchase_limit'
  102. },{
  103. label: '含税价',
  104. key: 'tax_price'
  105. },{
  106. label: '不含税价',
  107. key: 'non_tax_price'
  108. },{
  109. label: '操作',
  110. key: 'operation'
  111. }],
  112. contents: [],
  113. is_show: false,
  114. relation_list: [], // 关联食堂列表
  115. node_top: 0,
  116. code: '', // 订单号,批次号,如果有
  117. type: 0,
  118. deadline_start: '',
  119. deadline_end: '',
  120. table_loading: true,
  121. searchValue: '' // 搜索内容
  122. }
  123. },
  124. computed: {
  125. selectName(){
  126. let arr = [];
  127. this.relation_list.map(item => {
  128. if(item.checked){
  129. arr.push(item.canteen_name);
  130. }
  131. });
  132. let str = '请选择...';
  133. if(arr.length > 0){
  134. str = arr.join(',');
  135. }
  136. return str;
  137. }
  138. },
  139. onLoad(options){
  140. this.code = options.code || '';
  141. this.type = options.type || 0;
  142. if(options.type == 1){
  143. // 编辑,不可更换食堂
  144. this.materialListByOrder();
  145. }else if(options.type == 2){
  146. // 复用订单号
  147. this.materialListByOrder();
  148. }else if(options.type == 3){
  149. // 复用批次号
  150. this.materialListByBatch();
  151. }else{
  152. // 单纯发起报价
  153. this.getMaterialList();
  154. }
  155. },
  156. onReady(){
  157. let that = this;
  158. let info = uni.createSelectorQuery().select(".relation");
  159.     info.boundingClientRect(function(data) {
  160. let num = app.globalData.customBarH;
  161. num += data.height;
  162. num += data.top;
  163. that.node_top = num;
  164.    }).exec()
  165. },
  166. onPageScroll(){
  167. if(this.is_show){
  168. this.is_show = false;
  169. }
  170. },
  171. methods: {
  172. // 搜索input值被改变
  173. inputChange(event){
  174. if(timer){
  175. clearTimeout(timer);
  176. timer = null;
  177. }
  178. timer = setTimeout(() => {
  179. this.searchValue = event.detail.value;
  180. }, 1000);
  181. },
  182. // 搜索按下回车
  183. inputConfirm(event){
  184. this.searchValue = event.detail.value;
  185. },
  186. // 日期选择器值被改变
  187. pickerChange(event, current_name){
  188. console.log(current_name)
  189. if(current_name == 'deadline_start') {
  190. // PS 获取30天后日期
  191. var date1 = new Date(event.detail.value);
  192. var date2 = new Date(date1);
  193. date2.setDate(date1.getDate() + 30);
  194. console.log(this.$shared.recordTime(date2, '-', 'date'))
  195. this[current_name] = event.detail.value;
  196. this.deadline_end = this.$shared.recordTime(date2, '-', 'date')
  197. }else {
  198. this[current_name] = event.detail.value;
  199. }
  200. },
  201. // 获取物资列表
  202. getMaterialList(){
  203. this.$http(this.API.API_SUPPLIER_MATERIALLIST).then(res => {
  204. let list = res.data.spec || [];
  205. let contents = list.map(item => {
  206. return {
  207. name: item?.material?.m_name || '',
  208. material_id: item?.material?.id || 0,
  209. spec: item.name,
  210. spec_id: item.id,
  211. brand: item?.material?.brand || '',
  212. quality_level: item?.material?.quality_level || '',
  213. number: item?.material?.m_sn || '',
  214. purchase_limit: {edit: true, value: 1},
  215. tax_price: {edit: true, value: ''},
  216. non_tax_price: {edit: true, value: ''},
  217. operation: {button: true, key: 'delete', value: '删除'},
  218. unit: item?.material?.unit?.unit_name || '',
  219. category: item?.material?.category?.m_cate_name || ''
  220. }
  221. })
  222. this.contents = contents;
  223. this.table_loading = false;
  224. this.getCanteenList();
  225. })
  226. },
  227. // 复用报价订单号 & 编辑共用
  228. materialListByOrder(){
  229. this.$http(this.API.API_SUPPLIER_QUOTATIONREUSEBYORDER, {
  230. q_sn: this.code
  231. }).then(res => {
  232. let list = res.data.order || [];
  233. let canteen = res.data.canteen || [];
  234. // 处理表格显示
  235. let contents = list.map(item => {
  236. let obj = {
  237. name: item?.material?.m_name || '',
  238. material_id: item?.material?.id || 0,
  239. spec: item.name,
  240. spec_id: item.id,
  241. brand: item?.material?.brand || '',
  242. quality_level: item?.material?.quality_level || '',
  243. number: item?.material?.m_sn || '',
  244. purchase_limit: {edit: true, value: item?.quotation_item?.purchase_limit || ''},
  245. tax_price: {edit: true, value: item?.quotation_item?.tax_price || ''},
  246. non_tax_price: {edit: true, value: item?.quotation_item?.non_tax_price || ''},
  247. quotation_id: item?.quotation_item?.id || 0,
  248. operation: {button: true, key: 'delete', value: '删除'},
  249. unit: item?.material?.unit?.unit_name || '',
  250. category: item?.material?.category?.m_cate_name || ''
  251. }
  252. if(item?.material?.state && item?.material?.state != '启用'){
  253. obj.disabled = true;
  254. }
  255. return obj;
  256. })
  257. this.contents = contents;
  258. this.table_loading = false;
  259. // 处理报价生效、失效时间
  260. let deadline_start = '';
  261. let deadline_end = '';
  262. if(list[0] && list[0]?.quotation_item?.quotation){
  263. let quotation = list[0]?.quotation_item?.quotation || {};
  264. if(quotation.deadline_start){
  265. deadline_start = quotation.deadline_start.split(' ')[0];
  266. }
  267. if(quotation.deadline){
  268. deadline_end = quotation.deadline.split(' ')[0];
  269. }
  270. }
  271. this.deadline_start = deadline_start;
  272. this.deadline_end = deadline_end;
  273. this.getCanteenList(canteen);
  274. })
  275. },
  276. // 复用批次号
  277. materialListByBatch(){
  278. this.$http(this.API.API_SUPPLIER_QUOTATIONREUSEBYBATCH, {
  279. batch_sn: this.code
  280. }).then(res => {
  281. console.log("materialListByBatch", res);
  282. let list = res.data.order || [];
  283. let canteen = res.data.canteen || [];
  284. // 处理表格显示
  285. let contents = list.map(item => {
  286. return {
  287. name: item?.material?.m_name || '',
  288. material_id: item?.material?.id || 0,
  289. spec: item.name,
  290. spec_id: item.id,
  291. brand: item?.material?.brand || '',
  292. quality_level: item?.material?.quality_level || '',
  293. number: item?.material?.m_sn || '',
  294. purchase_limit: {edit: true, value: item?.quotation?.purchase_limit || ''},
  295. tax_price: {edit: true, value: item?.quotation?.tax_price || ''},
  296. non_tax_price: {edit: true, value: item?.quotation?.non_tax_price || ''}
  297. }
  298. })
  299. this.contents = contents;
  300. this.table_loading = false;
  301. // 处理报价生效、失效时间
  302. let deadline_start = '';
  303. let deadline_end = '';
  304. if(list[0] && list[0]?.quotation_item?.quotation){
  305. let quotation = list[0]?.quotation_item?.quotation || {};
  306. if(quotation.deadline_start){
  307. deadline_start = quotation.deadline_start.split(' ')[0];
  308. }
  309. if(quotation.deadline){
  310. deadline_end = quotation.deadline.split(' ')[0];
  311. }
  312. }
  313. this.deadline_start = deadline_start;
  314. this.deadline_end = deadline_end;
  315. this.getCanteenList(canteen);
  316. })
  317. },
  318. // 关联食堂列表
  319. getCanteenList(canteen = []){
  320. this.$http(this.API.API_SUPPLIER_CANTEENLIST).then(res => {
  321. let list = res.data.list.map(item => {
  322. item.checked = false;
  323. canteen.map(ct => {
  324. if(ct == item.id){
  325. item.checked = true;
  326. }
  327. })
  328. return item;
  329. })
  330. this.relation_list = list;
  331. })
  332. },
  333. // 监听表格被输入
  334. onInputChange(event){
  335. this.contents[event.contentIndex][event.key].value = event.detailValue;
  336. },
  337. // table操作按钮被点击
  338. onButtonClick(event){
  339. if(event.content.key == 'delete'){
  340. let contentIndex = event.contentIndex;
  341. let name = event.lineData.name;
  342. let spec = event.lineData.spec;
  343. uni.showModal({
  344. title: '温馨提示',
  345. content: `确定删除 ${name}-${spec} 吗?`,
  346. confirmColor: '#1833F2',
  347. success: result => {
  348. if(result.confirm){
  349. this.contents.splice(contentIndex, 1);
  350. }
  351. }
  352. })
  353. }
  354. },
  355. // 切换显示关联食堂modal
  356. switchRelation(){
  357. if(this.type == 1) return this.$msg('编辑不可更换关联食堂哦');
  358. this.is_show = !this.is_show;
  359. },
  360. // 选择食堂
  361. selectItem(index){
  362. this.relation_list[index].checked = !this.relation_list[index].checked;
  363. },
  364. // 报价订单编辑时保存
  365. editMaterial(_t){
  366. // 物资列表
  367. let list = [];
  368. this.contents.map(item => {
  369. list.push({
  370. id: item.quotation_id,
  371. tax_price: item.tax_price.value,
  372. non_tax_price: item.non_tax_price.value,
  373. purchase_limit: Number(item.purchase_limit.value) || 1
  374. })
  375. });
  376. // 操作状态,是保存还是直接发起
  377. let state = ['待发起', '待审核'][_t];
  378. this.$http(this.API.API_SUPPLIER_QUOTATIONSAVE, {
  379. data: list,
  380. state: state,
  381. q_sn: this.code,
  382. start: this.deadline_start,
  383. end: this.deadline_end
  384. }).then(res => {
  385. this.$msg('操作成功').then(result => {
  386. this.$toBack();
  387. })
  388. })
  389. },
  390. // 保存
  391. save(_t){
  392. // 拦截是编辑的情况
  393. if(this.type == 1){
  394. this.editMaterial(_t);
  395. return;
  396. }
  397. // 物资列表
  398. let list = [];
  399. this.contents.map(item => {
  400. if(item.tax_price.value && item.non_tax_price.value){
  401. list.push({
  402. m_id: item.material_id,
  403. m_spec_id: item.spec_id,
  404. tax_price: item.tax_price.value,
  405. non_tax_price: item.non_tax_price.value,
  406. purchase_limit: Number(item.purchase_limit.value) || 1
  407. })
  408. }
  409. });
  410. // 关联食堂
  411. let canteen_ids = [];
  412. this.relation_list.map(item => {
  413. if(item.checked){
  414. canteen_ids.push(item.id);
  415. }
  416. })
  417. if(canteen_ids.length <= 0){
  418. return this.$msg('您未选择关联食堂哦')
  419. }
  420. if(!this.deadline_start){
  421. return this.$msg('您未选择报价生效时间哦')
  422. }
  423. if(!this.deadline_end){
  424. return this.$msg('您未选择报价失效时间哦')
  425. }
  426. if(list.length <= 0){
  427. return this.$msg('请补充完整物资报价信息')
  428. }
  429. // 操作状态,是保存还是直接发起
  430. let state = ['待发起', '待审核'][_t];
  431. this.$http(this.API.API_SUPPLIER_QUOTATIONAPPLY, {
  432. data: list,
  433. state: state,
  434. canteen_ids: canteen_ids,
  435. start: this.deadline_start,
  436. end: this.deadline_end
  437. }).then(res => {
  438. this.$msg(res.data).then(result => {
  439. this.$toBack();
  440. })
  441. })
  442. }
  443. }
  444. }
  445. </script>
  446. <style>
  447. page{
  448. overflow: hidden;
  449. }
  450. </style>
  451. <style lang="scss" scoped="scoped">
  452. .lf-m-t-5{
  453. margin-top: 5rpx;
  454. }
  455. .box{
  456. padding: 30rpx 32rpx;
  457. width: 100%;
  458. height: max-content;
  459. box-sizing: border-box;
  460. }
  461. .title{
  462. color: #222222;
  463. font-size: 28rpx;
  464. font-weight: bold;
  465. }
  466. .fixed-bottom{
  467. position: fixed;
  468. bottom: 0rpx;
  469. left: 0rpx;
  470. z-index: 99;
  471. width: 750rpx;
  472. height: 98rpx;
  473. display: flex;
  474. justify-content: center;
  475. align-items: center;
  476. border-top: 1rpx solid #E5E5E5;
  477. background-color: #fff;
  478. .btn{
  479. width: 320rpx;
  480. height: 82rpx;
  481. border-radius: 41rpx;
  482. margin: 0;
  483. padding: 0;
  484. font-size: 32rpx;
  485. display: flex;
  486. justify-content: center;
  487. align-items: center;
  488. }
  489. .btn1{
  490. border: 2rpx solid #555555;
  491. opacity: .5;
  492. }
  493. .btn2{
  494. background: #1833F2;
  495. color: #FFFFFF;
  496. margin-left: 50rpx;
  497. }
  498. }
  499. .relation{
  500. position: relative;
  501. border-bottom: 1rpx solid #E5E5E5;
  502. }
  503. .mask{
  504. position: fixed;
  505. background-color: rgba(0,0,0,0.4);
  506. width: 100%;
  507. // top: 149px;
  508. bottom: 0;
  509. left: 0;
  510. z-index: 100;
  511. .list{
  512. min-height: max-content;
  513. max-height: 500rpx;
  514. overflow: scroll;
  515. background-color: #FFFFFF;
  516. width: 100%;
  517. .item{
  518. height: 92rpx;
  519. padding: 0 32rpx;
  520. border-bottom: 1rpx solid #E5E5E5;
  521. color: #222222;
  522. font-size: 28rpx;
  523. }
  524. }
  525. }
  526. </style>