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

497 lines
14 KiB

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