edit.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. <?php
  2. use common\helpers\ComponentHelper;
  3. ComponentHelper::loadComponentView('com-district-rule');
  4. ComponentHelper::loadComponentView('com-district-single-rule');
  5. ?>
  6. <div id="app" v-cloak>
  7. <el-card shadow="never" style="border:0" class="box-card" body-style="background-color: #f3f3f3;padding: 10px 0 0;" class="box-card" v-loading="cardLoading">
  8. <div slot="header">
  9. <div flex="cross:center box:first">
  10. <div><span @click="$navigate({r:'mall/freight/rules'})" class="text">运费规则</span>/添加规则</div>
  11. </div>
  12. </div>
  13. <div class="form-body">
  14. <el-form :model="form" :rules="rules" size="small" ref="form" label-width="120px">
  15. <el-form-item label="规则名称" prop="name">
  16. <el-input size="small" v-model="form.name"></el-input>
  17. </el-form-item>
  18. <el-form-item label="计费方式" prop="type">
  19. <el-radio name="type" :label="1" v-model="form.type">按重计费</el-radio>
  20. <el-radio name="type" :label="2" v-model="form.type">按件计费</el-radio>
  21. </el-form-item>
  22. <el-form-item label="按商品计算" prop="compute_type">
  23. <el-radio name="type" :label="1" v-model="form.compute_type">按不同商品计算</el-radio>
  24. <el-radio name="type" :label="2" v-model="form.compute_type">按同件商品计算</el-radio>
  25. <div class="tips-text" v-if="form.compute_type == 1" style="line-height: 24px;">
  26. 运费规则:首件/重 15元,续件/重 1.5元<br />
  27. 商品A*1件 = 15元,商品A*2件 = 16.5元<br />
  28. 商品A*1件 + 商品B*1件 = 30元, 商品A*2件 + 商品B*1件 = 31.5元
  29. </div>
  30. <div class="tips-text" v-if="form.compute_type == 2" style="line-height: 24px;">
  31. 运费规则:首件/重 15元,续件/重 1.5元<br />
  32. 商品A*1件 = 15元,商品A*2件 = 16.5元<br />
  33. 商品A*1件 + 商品B*1件 = 16.5元, 商品A*2件 + 商品B*1件 = 18元<br />
  34. 规则:首件 + 续件 + 续件 + 续件……【就算不同商品也是按续件算】<br />
  35. 注意:若购物车内不同的商品使用的运费模板也不一样,则会根据不同模板来计算
  36. </div>
  37. </el-form-item>
  38. <el-form-item label="选择地区" prop="type">
  39. <el-radio-group name="select_com" v-model="form.select_com" @change="getSelectCom">
  40. <el-radio :disabled="form.id ? true : false" :label="0">多选地区</el-radio>
  41. <el-radio :disabled="form.id ? true : false" :label="1">单选地区</el-radio>
  42. </el-radio-group>
  43. </el-form-item>
  44. <el-form-item label="运费规则" prop="rule" required>
  45. <div class="el_freight_rules" v-if="form.rule"v-for="(item, index) in form.rule" :key="item.id">
  46. <div class="el_freight_rules_header">
  47. <div class="el_freight_rules_header_left">
  48. <el-breadcrumb separator="/">
  49. <el-breadcrumb-item>首重/件(克/个):{{item.first}}</el-breadcrumb-item>
  50. <el-breadcrumb-item>首费(元):{{item.firstPrice}}</el-breadcrumb-item>
  51. <el-breadcrumb-item>续重/件(克/个):{{item.second}}</el-breadcrumb-item>
  52. <el-breadcrumb-item>续费(元):{{item.secondPrice}}</el-breadcrumb-item>
  53. </el-breadcrumb>
  54. <el-breadcrumb separator="/"
  55. v-if="item.is_enable_ladder_condition"
  56. :key="ladder_condition_index"
  57. v-for="(ladder_condition_item, ladder_condition_index) in item.ladder_condition"
  58. style="margin-top: 10px;">
  59. <el-breadcrumb-item>商品累计达到 {{ ladder_condition_item.condition_value }} {{ getTypeTextMap[form.type] }},运费 {{ ladder_condition_item.money }} 元</el-breadcrumb-item>
  60. </el-breadcrumb>
  61. </div>
  62. <div class="el_freight_rules_header_right">
  63. <el-button type="text" @click="editDistrict(item, index)" size="small" circle>
  64. <el-tooltip class="item" effect="dark" content="编辑" placement="top">
  65. <img src="resources/img/mall/edit.png" alt="">
  66. </el-tooltip>
  67. </el-button>
  68. <el-button style="margin-left: 0" type="text" @click="deleteDetail(index)" size="small"
  69. circle>
  70. <el-tooltip class="item" effect="dark" content="删除" placement="top">
  71. <img src="resources/img/mall/del.png" alt="">
  72. </el-tooltip>
  73. </el-button>
  74. </div>
  75. </div>
  76. <div class="el_freight_rules_region">
  77. <div class="region_left_title">区域:</div>
  78. <div class="region_right_item">
  79. <div class="region_right_item_left" :class="{region_right_item_left_hide:index!==is_region_show}">
  80. <el-tag type="info" style="margin: 5px;border:0" v-for="(value, key) in item.list">
  81. {{value.name}}
  82. </el-tag>
  83. </div>
  84. <div class="region_right_item_right"
  85. :class="( index===is_region_show ? 'el-icon-arrow-down' : 'el-icon-arrow-right')"
  86. @click="displayRegionAll(item,index)"></div>
  87. </div>
  88. </div>
  89. </div>
  90. <el-button type="text" @click="openDistrict"><i class="el-icon-plus">新增规则</i></el-button>
  91. </el-form-item>
  92. <el-button class="button-item" :loading="btnLoading" type="primary" @click="submit('form')" size="small">保存</el-button>
  93. </el-form>
  94. </div>
  95. </el-card>
  96. <el-dialog :title="title" :visible.sync="dialogVisible" width="50%" :close-on-click-modal="false">
  97. <div style="margin-bottom: 1rem;">
  98. <el-form :model="rule" ref="rule" label-width="130px" :rules="ruleRules">
  99. <div flex="dir:left box:mean">
  100. <div style="padding: 0 1rem;">
  101. <el-form-item prop="first" :label="form.type == 1 ? '首重(克):' : '首件(个):'">
  102. <el-input @blur="rule.first = Math.abs(parseInt(rule.first))" v-model.number="rule.first" min="0" type="number"></el-input>
  103. </el-form-item>
  104. </div>
  105. <div style="padding: 0 1rem;">
  106. <el-form-item prop="firstPrice" label="首费(元)">
  107. <el-input @blur="rule.firstPrice = Math.abs(keepTwoDecimalPlaces(rule.firstPrice))" v-model.number="rule.firstPrice" min="0" type="number"></el-input>
  108. </el-form-item>
  109. </div>
  110. </div>
  111. <div flex="dir:left box:mean">
  112. <div style="padding: 0 1rem;">
  113. <el-form-item prop="second" :label="form.type == 1 ? '续重(克):' : '续件(个):'">
  114. <el-input @blur="rule.second = Math.abs(parseInt(rule.second))" v-model.number="rule.second" min="0" type="number"></el-input>
  115. </el-form-item>
  116. </div>
  117. <div style="padding: 0 1rem;">
  118. <el-form-item prop="secondPrice" label="续费(元)">
  119. <el-input @blur="rule.secondPrice = Math.abs(keepTwoDecimalPlaces(rule.secondPrice))" v-model.number="rule.secondPrice" min="0" type="number"></el-input>
  120. </el-form-item>
  121. </div>
  122. </div>
  123. <el-form-item v-if="form.select_com == 1" prop="list" label="地区选择">
  124. <com-district-single-rule :rule="form.rule" ref="editSingle" :not-rule="notChoiceRule" :edit="rule.list" @selected="selectDistrict"
  125. :level="3"></com-district-single-rule>
  126. </el-form-item>
  127. <el-form-item label="是否启用阶梯条件">
  128. <el-switch v-model="rule.is_enable_ladder_condition"
  129. :active-value="1"
  130. :inactive-value="0">
  131. </el-switch>
  132. </el-form-item>
  133. <el-form-item v-if="rule.is_enable_ladder_condition">
  134. <el-table :data="rule.ladder_condition" style="width: 100%">
  135. <el-table-column label="阶梯条件" align="center">
  136. <template slot-scope="scope">
  137. <el-row style="display: flex;align-items: center;">
  138. <el-col :span="8">
  139. 商品累计达到
  140. </el-col>
  141. <el-col :span="16">
  142. <el-input size="mini"
  143. v-model="rule.ladder_condition[scope.$index].condition_value"
  144. style="float: left;"
  145. @blur="conditionValueBlur(scope.$index)"
  146. type="number">
  147. <template slot="append">
  148. {{ getTypeTextMap[form.type] }}
  149. </template>
  150. </el-input>
  151. </el-col>
  152. </el-row>
  153. </template>
  154. </el-table-column>
  155. <el-table-column label="运费" align="center">
  156. <template slot-scope="scope">
  157. <el-input size="mini"
  158. style="width: 250px;"
  159. v-model="rule.ladder_condition[scope.$index].money"
  160. min="0"
  161. @blur="moneyBlur(scope.$index)"
  162. type="number">
  163. <template slot="append">元</template>
  164. </el-input>
  165. </template>
  166. </el-table-column>
  167. <el-table-column prop="date" label="操作" align="center" width="100px">
  168. <template slot-scope="scope">
  169. <el-button type="primary" size="mini" @click="rule.ladder_condition.splice(scope.$index, 1)">删除</el-button>
  170. </template>
  171. </el-table-column>
  172. </el-table>
  173. <el-button type="primary" size="mini" style="margin-top: 20px;" @click="addLadderCondition">添加阶梯条件</el-button>
  174. </el-form-item>
  175. <el-form-item v-if="form.select_com == 0" prop="list" label="地区选择">
  176. <com-district-rule :rule="form.rule" :edit="rule.list" :not-rule="notChoiceRule" @selected="selectDistrict" :dialog-visibles="dialogVisible"
  177. :level="3" ></com-district-rule>
  178. </el-form-item>
  179. <div style="text-align: right;margin-top: 1rem;">
  180. <el-button type="primary" @click="districtConfirm('rule')">
  181. 确定选择
  182. </el-button>
  183. </div>
  184. </el-form>
  185. </div>
  186. </el-dialog>
  187. </div>
  188. <script>
  189. const app = new Vue({
  190. el: '#app',
  191. data() {
  192. let min_number = (rule, value, callback) => {
  193. if (value < 0) {
  194. callback(new Error('输入值必须大于0'));
  195. } else {
  196. callback();
  197. }
  198. };
  199. return {
  200. form: {
  201. name: '',
  202. type: -1,
  203. compute_type: 1,
  204. select_com: 0,
  205. rule: []
  206. },
  207. btnLoading: false,
  208. is_region_show: true,
  209. rules: {
  210. name: [
  211. {
  212. required: true,
  213. message: '请输入规则名称',
  214. trigger: 'blur'
  215. }
  216. ],
  217. rule: [
  218. {
  219. required: true,
  220. message: '请输入运费规则'
  221. }
  222. ]
  223. },
  224. cardLoading: false,
  225. dialogVisible: false,
  226. is_add: false,
  227. title: '新增规则',
  228. rule: {
  229. first: 0,
  230. firstPrice: 0,
  231. second: 0,
  232. secondPrice: 0,
  233. list: [],
  234. is_enable_ladder_condition: 0,
  235. ladder_condition: [],
  236. },
  237. notChoiceRule:[],//不能选择id
  238. ruleRules: {
  239. first: [
  240. {
  241. validator: min_number,
  242. trigger: 'blur'
  243. },
  244. {
  245. type: 'number',
  246. message: '请输入数字',
  247. trigger: 'blur',
  248. required: true
  249. }
  250. ],
  251. firstPrice: [
  252. {
  253. validator: min_number,
  254. trigger: 'blur'
  255. },
  256. {
  257. type: 'number',
  258. message: '请输入数字',
  259. trigger: 'blur',
  260. required: true
  261. }
  262. ],
  263. second: [
  264. {
  265. validator: min_number,
  266. trigger: 'blur'
  267. },
  268. {
  269. type: 'number',
  270. message: '请输入数字',
  271. trigger: 'blur',
  272. required: true
  273. }
  274. ],
  275. secondPrice: [
  276. {
  277. validator: min_number,
  278. trigger: 'blur'
  279. },
  280. {
  281. type: 'number',
  282. message: '请输入数字',
  283. trigger: 'blur',
  284. required: true
  285. }
  286. ],
  287. list: [
  288. {
  289. type: 'array',
  290. message: '请选择地区',
  291. trigger: 'blur',
  292. required: true
  293. }
  294. ]
  295. },
  296. editIndex:-1//当前修改的下标
  297. }
  298. },
  299. mounted: function () {
  300. if (getQuery('id')) {
  301. this.getDetail(getQuery('id'));
  302. } else {
  303. this.form.type = 1;
  304. }
  305. },
  306. watch: {
  307. newType(val, oldVal) {
  308. if (oldVal == -1) {
  309. } else {
  310. this.form.rule.splice(0, this.form.rule.length);
  311. }
  312. }
  313. },
  314. computed: {
  315. newType() {
  316. return this.form.type;
  317. },
  318. getTypeTextMap() {
  319. return {1: 'kg', 2: '件'}
  320. }
  321. },
  322. methods: {
  323. Cancel() {
  324. window.history.go(-1)
  325. },
  326. getSelectCom(){// 进行单选多选切换时原来的规则清空
  327. this.form.rule = [];
  328. },
  329. submit(formName) {
  330. this.btnLoading = true;
  331. this.$refs[formName].validate((valid) => {
  332. if (valid) {
  333. this.form.name = this.form.name.toString()
  334. request({
  335. params: {
  336. r: 'mall/freight/edit',
  337. id: getQuery('id')
  338. },
  339. method: 'post',
  340. data: {
  341. form:JSON.stringify(this.form)
  342. }
  343. }).then(e => {
  344. this.btnLoading = false;
  345. if (e.data.code == 0) {
  346. this.$message.success(e.data.msg);
  347. navigateTo({
  348. r: 'mall/freight/rules',
  349. tab: 'second'
  350. })
  351. } else {
  352. this.$message.error(e.data.msg);
  353. }
  354. }).catch(e => {
  355. this.btnLoading = false;
  356. this.$message.error(e.data.msg);
  357. });
  358. } else {
  359. console.log('error submit!!');
  360. this.btnLoading = false;
  361. return false;
  362. }
  363. });
  364. },
  365. openDistrict() {
  366. if(this.form.select_com == 1 && this.$refs['editSingle'] !== undefined){
  367. this.$refs['editSingle'].backList = []
  368. }
  369. let self = this
  370. self.title = '新增规则';
  371. self.dialogVisible = true;
  372. this.getNotRule(null);
  373. self.rule = {
  374. first: 0,
  375. firstPrice: 0,
  376. second: 0,
  377. secondPrice: 0,
  378. list: [],
  379. is_enable_ladder_condition: 0,
  380. ladder_condition: [],
  381. };
  382. self.is_add = true;
  383. },
  384. editDistrict(row, index) {
  385. this.title = '编辑规则';
  386. this.dialogVisible = true;
  387. this.getNotRule(index);
  388. this.rule = JSON.parse(JSON.stringify(row));
  389. this.is_add = false;
  390. this.editIndex = index;
  391. if (this.form.select_com == 1) {
  392. setTimeout(()=>{
  393. this.$refs['editSingle'].backList = this.form.rule[index].list
  394. },800)
  395. }
  396. },
  397. getNotRule(index) {// 获取不能选择城市区域id
  398. //获取其它列表选择的区域id
  399. if (this.form.rule.length > 0) {
  400. let not_choice_rule = [];
  401. this.form.rule.forEach(function (item,not_index) {
  402. if (index !== null && not_index === index) return false;
  403. if (item.list.length>0) {
  404. item.list.forEach(function (item_value,item_index) {
  405. not_choice_rule.push(item_value.id);
  406. })
  407. }
  408. })
  409. this.notChoiceRule = not_choice_rule;
  410. }
  411. },
  412. deleteDetail(index) {
  413. this.$confirm("删除该运费规则将不可用,是否确定删除?", "提示", {
  414. type: "warning"
  415. }).then((res) => {
  416. this.form.rule.splice(index, 1);
  417. request({
  418. params: {
  419. r: 'mall/freight/edit',
  420. id: getQuery('id')
  421. },
  422. method: 'post',
  423. data: {
  424. form:JSON.stringify(this.form)
  425. }
  426. }).then(e => {
  427. this.btnLoading = false;
  428. if (e.data.code == 0) {
  429. this.$message({
  430. type: 'success',
  431. message: e.data.msg,
  432. duration: 2000,
  433. onClose: function () {
  434. window.location.reload();
  435. }
  436. });
  437. } else {
  438. this.$message.error(e.data.msg);
  439. }
  440. }).catch(e => {
  441. this.$message.error(e.data.msg);
  442. });
  443. }).catch(() => {})
  444. },
  445. selectDistrict(e) {
  446. let list = [];
  447. for (let i in e) {
  448. let obj = {
  449. id: e[i].id,
  450. name: e[i].name
  451. };
  452. list.push(obj);
  453. }
  454. this.rule.list = list;
  455. },
  456. districtConfirm(formName) {
  457. this.$refs[formName].validate((valid) => {
  458. if (valid) {
  459. // 验证阶梯条件
  460. if (!this.checkLadderCondition()) {
  461. return false
  462. }
  463. if (this.is_add) {
  464. this.form.rule.push(this.rule);
  465. } else {
  466. if(this.editIndex !=-1){
  467. this.form.rule.splice(this.editIndex, 1,this.rule);
  468. }
  469. }
  470. this.dialogVisible = false;
  471. this.$refs['form'].validate((valid) => {
  472. return false;
  473. });
  474. } else {
  475. console.log('error submit!!');
  476. return false;
  477. }
  478. });
  479. },
  480. getDetail(id = 0) {
  481. let self = this;
  482. self.cardLoading = true;
  483. request({
  484. params: {
  485. r: 'mall/freight/edit',
  486. id: id
  487. },
  488. method: 'get'
  489. }).then(e => {
  490. self.cardLoading = false;
  491. if (e.data.code == 0) {
  492. self.form = Object.assign(self.form, e.data.data.detail);
  493. if (isEmpty(self.form.select_com)) self.form.select_com = 0;
  494. } else {
  495. self.$message.error(e.data.msg);
  496. }
  497. }).catch(e => {
  498. self.cardLoading = false;
  499. });
  500. },
  501. displayRegionAll(item, index) {// 点击显示对应全部区域
  502. this.is_region_show = this.is_region_show !== index ? index : true;
  503. },
  504. keepTwoDecimalPlaces(num) {
  505. return Math.round(num * 100) / 100;
  506. },
  507. addLadderCondition() {
  508. this.rule.ladder_condition = this.rule.ladder_condition??[]
  509. this.rule.ladder_condition.push({condition_value: 0, money: 0})
  510. },
  511. returnNumberFormatByType(value) {
  512. let res = 0;
  513. if (this.form.type == 1) {
  514. res = this.keepTwoDecimalPlaces(value)
  515. } else if (this.form.type == 2) {
  516. res = parseInt(value)
  517. }
  518. return res
  519. },
  520. checkLadderCondition() {
  521. let uniqueMap = {}
  522. for (const item of this.rule.ladder_condition) {
  523. item.condition_value = this.returnNumberFormatByType(item.condition_value)
  524. item.money = this.keepTwoDecimalPlaces(item.money)
  525. if (item.condition_value in uniqueMap) {
  526. this.$message.error('阶梯条件相同,无法提交');
  527. return false
  528. }
  529. uniqueMap[item.condition_value] = 1
  530. }
  531. return true
  532. },
  533. conditionValueBlur(index) {
  534. this.rule.ladder_condition[index].condition_value = Math.abs(this.returnNumberFormatByType(this.rule.ladder_condition[index].condition_value))
  535. },
  536. moneyBlur(index) {
  537. this.rule.ladder_condition[index].money = Math.abs(this.keepTwoDecimalPlaces(this.rule.ladder_condition[index].money))
  538. },
  539. }
  540. });
  541. </script>
  542. <style lang="scss">
  543. .el_freight_rules{
  544. display: flex;
  545. align-items: center;
  546. flex-direction: column;
  547. border: 1px solid #ebebeb;
  548. border-radius: 3px;
  549. transition: .2s;
  550. min-width: 700px;
  551. padding: 5px 15px;
  552. margin-bottom: 15px;
  553. }
  554. .el_freight_rules .el_freight_rules_header {
  555. display: flex;
  556. justify-content: space-between;
  557. align-items: center;
  558. width: 100%;
  559. }
  560. .el_freight_rules .el_freight_rules_region {
  561. display: flex;
  562. justify-content: flex-start;
  563. width: 100%;
  564. }
  565. .el_freight_rules_region .region_left_title{
  566. width: 50px;
  567. }
  568. .region_right_item_left_hide{
  569. display: -webkit-box;
  570. -webkit-line-clamp: 1;
  571. -webkit-box-orient: vertical;
  572. overflow: hidden;
  573. text-overflow: ellipsis;
  574. max-height: 3.0em; /* 高度为字体大小的两倍 */
  575. line-height: 1.5em; /* 行高 */
  576. height: 3.0em; /* 高度为行高的两倍 */
  577. }
  578. .region_right_item{
  579. display: flex;
  580. justify-content: space-between;
  581. width: 100%;
  582. }
  583. .el-icon-arrow-right, .el-icon-arrow-down {
  584. margin-top: 10px;
  585. font-size: 15px;
  586. }
  587. /*.is-leaf:nth-child(1),.is-leaf:nth-child(2) {
  588. .cell::before {
  589. content: "* ";
  590. color: #f50d1a;
  591. }
  592. }*/
  593. .el-table_1_column_1.is-leaf, .el-table_1_column_2.is-leaf{
  594. .cell::before {
  595. content: "* ";
  596. color: #f50d1a;
  597. }
  598. }
  599. </style>