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

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