dislogOrganSet.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. <template>
  2. <div>
  3. <BaseDialog
  4. width="1800px"
  5. :isShow.sync="isShow"
  6. :title="title"
  7. @close="close"
  8. @submit="submitForm"
  9. @open="init"
  10. >
  11. <div class="bop-tip">
  12. <div><i class="el-icon-warning-outline"></i>说明</div>
  13. <div>
  14. 如果提成方式是按阶梯价计算,则需设置阶梯价格区间(最高价无穷大,则填写
  15. “ * ” )。如果无需按阶梯价计算提成,留空即可。
  16. </div>
  17. </div>
  18. <el-form
  19. inline
  20. hide-required-asterisk
  21. :model="form"
  22. :rules="rules"
  23. ref="form"
  24. >
  25. <div>
  26. <el-form-item prop="tpName" label="模板名称:" label-width="100px">
  27. <el-input
  28. placeholder="请输入模板名称"
  29. v-model="form.tpName"
  30. ></el-input>
  31. </el-form-item>
  32. <el-form-item prop="tenantId" label="">
  33. <el-select
  34. filterable
  35. v-model="form.tenantId"
  36. placeholder="请选择关联机构"
  37. >
  38. <el-option
  39. v-for="item in tenantList"
  40. :key="item.tenantId"
  41. :label="item.tenantName"
  42. :value="item.tenantId"
  43. ></el-option>
  44. </el-select>
  45. </el-form-item>
  46. <el-form-item label="">
  47. <el-checkbox
  48. :true-label="1"
  49. :false-label="0"
  50. v-model="form.defaultStatus"
  51. >默认</el-checkbox
  52. >
  53. </el-form-item>
  54. </div>
  55. <div v-for="(item, index) in form.itemList" :key="index">
  56. <el-form-item
  57. :prop="'itemList.' + index + '.itemName'"
  58. :label="index == 0 ? '成本设置:' : ' '"
  59. :rules="rules['itemName']"
  60. label-width="100px"
  61. >
  62. <el-input
  63. placeholder="请输入成本项名称"
  64. v-model="item.itemName"
  65. ></el-input>
  66. </el-form-item>
  67. <el-form-item
  68. label=""
  69. :prop="'itemList.' + index + '.itemCategory'"
  70. :rules="rules['itemCategory']"
  71. >
  72. <el-select v-model="item.itemCategory" placeholder="请选择成本类别">
  73. <el-option
  74. :label="item.categoryName"
  75. :value="item.categoryId"
  76. v-for="item in categoryList"
  77. :key="item.categoryId"
  78. ></el-option>
  79. </el-select>
  80. </el-form-item>
  81. <el-form-item
  82. label=""
  83. :prop="'itemList.' + index + '.educationTypeId'"
  84. :rules="rules['educationTypeId']"
  85. >
  86. <el-select
  87. @change="changeEdu(item)"
  88. v-model="item.educationTypeId"
  89. placeholder="请选择教育类型"
  90. >
  91. <el-option
  92. v-for="item in eduList"
  93. :key="item.id"
  94. :label="
  95. item.schemeName +
  96. (item.schemeName ? '-' : '') +
  97. item.educationName
  98. "
  99. :value="item.id"
  100. >
  101. </el-option>
  102. </el-select>
  103. </el-form-item>
  104. <el-form-item
  105. v-if="item.educationTypeId != -1"
  106. label=""
  107. :prop="'itemList.' + index + '.businessId'"
  108. :rules="rules['businessId']"
  109. >
  110. <el-select
  111. filterable
  112. v-model="item.businessId"
  113. placeholder="请选择业务层次"
  114. >
  115. <el-option
  116. v-for="level in backbusinessList(item.educationTypeId)"
  117. :key="level.businessId"
  118. :label="level.aliasName"
  119. :value="level.businessId"
  120. @click.native="changeBus(item, level.projectId)"
  121. >
  122. </el-option>
  123. </el-select>
  124. </el-form-item>
  125. <el-form-item
  126. label=""
  127. :prop="'itemList.' + index + '.itemType'"
  128. :rules="rules['itemType']"
  129. >
  130. <el-select v-model="item.itemType" placeholder="请选择成本类型">
  131. <el-option label="百分比" :value="1"></el-option>
  132. <el-option label="固定" :value="2"></el-option>
  133. </el-select>
  134. </el-form-item>
  135. <el-form-item
  136. label=""
  137. :prop="'itemList.' + index + '.minValue'"
  138. :rules="rules['minValue']"
  139. class="range"
  140. >
  141. <el-col :span="11">
  142. <el-input
  143. v-int
  144. placeholder="最低价"
  145. v-model.number="item.minValue"
  146. ></el-input>
  147. </el-col>
  148. <el-col class="line" :span="2" style="magrin: 10px">-</el-col>
  149. <el-col :span="11">
  150. <el-input
  151. @keyup.native="regValue(item)"
  152. placeholder="最高价"
  153. @change="changeMaxValue('itemList.' + index + '.minValue')"
  154. v-model.number="item.maxValue"
  155. ></el-input>
  156. </el-col>
  157. </el-form-item>
  158. <el-form-item
  159. v-if="item.itemType"
  160. class="ddd"
  161. label-width="0"
  162. :prop="'itemList.' + index + '.typeValue'"
  163. label=" "
  164. :rules="rules['typeValue']"
  165. >
  166. <el-input
  167. v-if="item.itemType == 1"
  168. placeholder="输入百分比"
  169. v-model="item.typeValue"
  170. key="2"
  171. v-int="{ max: 100 }"
  172. >
  173. <template slot="append"> % </template>
  174. </el-input>
  175. <el-input
  176. key="1"
  177. v-else
  178. placeholder="固定金额"
  179. v-model="item.typeValue"
  180. v-int
  181. >
  182. <template slot="append"> 元 </template>
  183. </el-input>
  184. </el-form-item>
  185. <template v-if="item.itemCategory == 1">
  186. <el-form-item label="">
  187. <el-checkbox
  188. :true-label="1"
  189. :false-label="0"
  190. v-model="item.dockStatus"
  191. >成本扣除</el-checkbox
  192. >
  193. </el-form-item>
  194. <template v-if="item.dockStatus == 1">
  195. <el-form-item
  196. label=""
  197. :prop="'itemList.' + index + '.dockType'"
  198. :rules="rules['dockType']"
  199. >
  200. <el-select v-model="item.dockType" placeholder="请选择扣除类型">
  201. <el-option label="百分比扣除" :value="1"></el-option>
  202. <el-option label="固定扣除" :value="2"></el-option>
  203. </el-select>
  204. </el-form-item>
  205. <el-form-item
  206. v-if="item.dockType"
  207. class="ddd"
  208. label-width="0"
  209. :prop="'itemList.' + index + '.dockValue'"
  210. label=" "
  211. :rules="rules['dockValue']"
  212. >
  213. <el-input
  214. v-if="item.dockType == 1"
  215. placeholder="输入百分比"
  216. v-model="item.dockValue"
  217. key="2"
  218. v-int="{ max: 100 }"
  219. >
  220. <template slot="append"> % </template>
  221. </el-input>
  222. <el-input
  223. key="1"
  224. v-else
  225. placeholder="固定金额"
  226. v-model="item.dockValue"
  227. v-int
  228. >
  229. <template slot="append"> 元 </template>
  230. </el-input>
  231. </el-form-item>
  232. </template>
  233. </template>
  234. <el-form-item label-width="0" label=" ">
  235. <div class="btns">
  236. <i @click="add(index, item)" class="el-icon-connection"></i>
  237. <i @click="add(index)" class="el-icon-circle-plus-outline"></i>
  238. <i
  239. v-if="index != 0"
  240. @click="del(index)"
  241. class="el-icon-remove-outline"
  242. ></i>
  243. </div>
  244. </el-form-item>
  245. </div>
  246. </el-form>
  247. </BaseDialog>
  248. </div>
  249. </template>
  250. <script>
  251. import {
  252. eduList,
  253. addCost,
  254. costDetail,
  255. editCost,
  256. categoryList,
  257. } from "@/api/financed/index";
  258. export default {
  259. name: "DislogSet",
  260. props: {
  261. dialogVisible: {
  262. type: Boolean,
  263. default: false,
  264. },
  265. // 0 新增 1修改 2复制 3订单成本设置 4批量设置
  266. type: {
  267. type: [String, Number],
  268. default: 0,
  269. },
  270. tpId: {
  271. type: [String, Number],
  272. default: "",
  273. },
  274. },
  275. data() {
  276. var checkMinValue = (rule, value, callback) => {
  277. const list = this.itemList[rule.field.split(".")[1]];
  278. const { maxValue, businessId, itemCategory } = list;
  279. if (maxValue || value || value === 0) {
  280. if (!value && value !== 0) {
  281. callback(new Error("请输入最低价"));
  282. } else if (!maxValue) {
  283. callback(new Error("请输入最高价"));
  284. } else if (maxValue <= value) {
  285. callback(new Error("最低价不能小于最高价"));
  286. }
  287. }
  288. if (businessId && itemCategory) {
  289. const levelList = this.itemList.filter(
  290. (e) =>
  291. e.businessId == list.businessId && e.itemCategory == itemCategory
  292. );
  293. if (levelList.length > 1) {
  294. const text = this.isHaveIntersect(levelList);
  295. text && callback(new Error(text));
  296. }
  297. }
  298. callback();
  299. };
  300. var checkEduId = (rule, value, callback) => {
  301. const { itemCategory } = this.itemList[rule.field.split(".")[1]];
  302. if (this.itemList.length > 1) {
  303. const levelList = this.itemList.filter(
  304. (e) => e.itemCategory && e.itemCategory == itemCategory
  305. );
  306. const len = levelList.length;
  307. if (len > 1) {
  308. const len1 = levelList.filter((e) => e.educationTypeId == -1).length;
  309. if (len1 > 0 && len1 != len) {
  310. callback(new Error("需统一不限!"));
  311. }
  312. }
  313. }
  314. callback();
  315. };
  316. var checkBusId = (rule, value, callback) => {
  317. const { educationTypeId, itemCategory } =
  318. this.itemList[rule.field.split(".")[1]];
  319. if (this.itemList.length > 1) {
  320. const levelList = this.itemList.filter(
  321. (e) =>
  322. itemCategory &&
  323. educationTypeId &&
  324. e.educationTypeId == educationTypeId &&
  325. e.itemCategory == itemCategory
  326. );
  327. const len = levelList.length;
  328. if (len > 1) {
  329. const len1 = levelList.filter((e) => e.businessId == -1).length;
  330. if (len1 > 0 && len1 != len) {
  331. callback(new Error("需统一不限!"));
  332. }
  333. }
  334. }
  335. callback();
  336. };
  337. return {
  338. form: {},
  339. rules: {
  340. tpName: [
  341. { required: true, message: "请输入模板名称", trigger: "blur" },
  342. ],
  343. tenantId: [
  344. { required: true, message: "请选择关联机构", trigger: "change" },
  345. ],
  346. itemName: [
  347. { required: true, message: "请输入成本项名称", trigger: "blur" },
  348. ],
  349. businessId: [
  350. { required: true, message: "请选择业务层次", trigger: "blur" },
  351. { validator: checkBusId, trigger: "change" },
  352. ],
  353. educationTypeId: [
  354. { required: true, message: "请选择教育类型", trigger: "change" },
  355. { validator: checkEduId, trigger: "change" },
  356. ],
  357. itemCategory: [
  358. { required: true, message: "请选择业务类型", trigger: "change" },
  359. ],
  360. itemType: [
  361. { required: true, message: "请选择成本类型", trigger: "change" },
  362. ],
  363. typeValue: [
  364. { required: true, message: "请输入成本值", trigger: "blur" },
  365. ],
  366. dockType: [
  367. { required: true, message: "请选择扣除类型", trigger: "change" },
  368. ],
  369. dockValue: [
  370. { required: true, message: "请输入扣除值", trigger: "blur" },
  371. ],
  372. minValue: [{ validator: checkMinValue, trigger: "blur" }],
  373. },
  374. tenantList: [],
  375. eduList: [],
  376. categoryList: [],
  377. };
  378. },
  379. methods: {
  380. init() {
  381. this.resetForm();
  382. if (this.type === 3) {
  383. this.getOrderCostDetail();
  384. } else if (this.type === 4) {
  385. } else {
  386. this.tpId && this.getCostDetail();
  387. }
  388. this.getCategoryList();
  389. this.getTenantList();
  390. this.getEduList();
  391. },
  392. getCategoryList() {
  393. categoryList({ status: "0,1" }).then((res) => {
  394. this.categoryList = res.rows;
  395. });
  396. },
  397. getOrderCostDetail() {
  398. this.$api.systemtopordercost(this.tpId).then((res) => {
  399. Object.keys(this.form).map((key) => {
  400. this.form[key] = res.data[key];
  401. });
  402. this.form.itemList.forEach((ele) => {
  403. if (ele.maxValue == -1) {
  404. ele.maxValue = "*";
  405. }
  406. });
  407. });
  408. },
  409. getCostDetail() {
  410. costDetail(this.tpId).then((res) => {
  411. if (this.type == 2) delete this.form["tpId"];
  412. Object.keys(this.form).map((key) => {
  413. this.form[key] = res.data[key];
  414. });
  415. this.form.itemList.forEach((ele) => {
  416. if (ele.maxValue == -1) {
  417. ele.maxValue = "*";
  418. }
  419. });
  420. });
  421. },
  422. getEduList() {
  423. if (this.eduList.length) return;
  424. eduList({}).then((res) => {
  425. this.eduList = [
  426. { schemeName: "", educationName: "不限", id: -1 },
  427. ...res.rows,
  428. ];
  429. });
  430. },
  431. backbusinessList(eduId) {
  432. if (!eduId || !this.eduList.length) return [];
  433. let data = this.eduList.find((e) => e.id == eduId);
  434. return data.businessList
  435. ? [
  436. { aliasName: "不限", businessId: -1, projectId: -1 },
  437. ...data.businessList,
  438. ]
  439. : [];
  440. },
  441. getTenantList() {
  442. if (this.tenantList.length) return;
  443. this.$api.systemtenantlist().then((res) => {
  444. this.tenantList = res.rows;
  445. });
  446. },
  447. changeEdu(data) {
  448. let value = data.educationTypeId == -1 ? -1 : undefined;
  449. data.businessId = value;
  450. data.projectId = value;
  451. },
  452. changeBus(data, projectId) {
  453. data.projectId = projectId;
  454. },
  455. add(index, data) {
  456. data = data ? JSON.parse(JSON.stringify(data)) : this.backItem();
  457. this.itemList.splice(index + 1, 0, data);
  458. },
  459. del(index) {
  460. this.itemList.splice(index, 1);
  461. },
  462. close() {
  463. this.$nextTick(() => {
  464. this.$refs["form"].resetFields();
  465. });
  466. },
  467. backItem() {
  468. return {
  469. projectId: undefined,
  470. itemName: undefined,
  471. itemCategory: undefined,
  472. businessId: undefined,
  473. educationTypeId: undefined,
  474. itemType: undefined,
  475. typeValue: undefined,
  476. minValue: undefined,
  477. maxValue: undefined,
  478. dockStatus: undefined,
  479. dockType: undefined,
  480. dockValue: undefined,
  481. };
  482. },
  483. resetForm() {
  484. this.form = {
  485. itemList: [this.backItem()],
  486. tpId: undefined,
  487. tpName: undefined,
  488. defaultStatus: 0,
  489. tenantId: undefined,
  490. };
  491. },
  492. cb() {
  493. this.$message.success(this.title + "成功");
  494. this.isShow = false;
  495. this.$emit("search");
  496. },
  497. submitForm() {
  498. this.$refs["form"].validate((valid) => {
  499. if (valid) {
  500. let form = JSON.parse(JSON.stringify(this.form));
  501. form.itemList.forEach((ele) => {
  502. if (ele.maxValue === "*") {
  503. ele.maxValue = -1;
  504. }
  505. });
  506. if (this.type === 3 || this.type === 4) {
  507. this.$api
  508. .systemtoporderupdatecost({
  509. costTpVo: form,
  510. orderSnList:
  511. this.type === 3 ? [this.tpId] : this.tpId?.split(","),
  512. })
  513. .then(this.cb);
  514. } else if (this.type !== 1) {
  515. addCost(form).then(this.cb);
  516. } else {
  517. editCost(form).then(this.cb);
  518. }
  519. } else {
  520. return false;
  521. }
  522. });
  523. },
  524. changeMaxValue(prop) {
  525. this.$refs.form.validateField(prop);
  526. },
  527. // 阶梯校验
  528. isHaveIntersect(list) {
  529. const isEmpty = list.some((e) => !e.minValue && !e.maxValue);
  530. if (isEmpty) {
  531. return "非阶梯计价只能存在一个";
  532. }
  533. let maxList = list.filter((e) => e.maxValue === "*");
  534. if (maxList.length > 1) {
  535. return "阶梯计价存在范围冲突";
  536. }
  537. list.sort((a, b) => {
  538. if (a.maxValue == "*") {
  539. return Number.MAX_VALUE;
  540. }
  541. if (b.maxValue == "*") {
  542. return -Number.MAX_VALUE;
  543. }
  544. return a.minValue - b.minValue;
  545. });
  546. for (let i = 0, len = list.length - 1; i < len; i++) {
  547. if (list[i].maxValue >= list[i + 1].minValue) {
  548. return "阶梯计价存在范围冲突";
  549. }
  550. }
  551. return;
  552. },
  553. regValue(data) {
  554. let { maxValue } = data;
  555. let val;
  556. if (maxValue.includes("*")) {
  557. val = "*";
  558. } else {
  559. val = maxValue.replace(/[^0-9]/g, "");
  560. }
  561. data.maxValue = val;
  562. },
  563. },
  564. computed: {
  565. isShow: {
  566. get() {
  567. return this.dialogVisible;
  568. },
  569. set(val) {
  570. this.$emit("update:dialogVisible", false);
  571. },
  572. },
  573. title() {
  574. return ["新增", "修改", "复制", "订单成本设置", "批量成本设置"][
  575. this.type
  576. ];
  577. },
  578. itemList() {
  579. return this.form.itemList;
  580. },
  581. },
  582. };
  583. </script>
  584. <style lang="scss" scoped>
  585. /deep/.el-input--medium .el-input__inner {
  586. width: 144px;
  587. }
  588. /deep/ .range {
  589. .el-form-item__content {
  590. width: 170px;
  591. }
  592. .el-input--medium .el-input__inner {
  593. width: 76px;
  594. }
  595. }
  596. /deep/ .ddd {
  597. margin-left: -10px;
  598. .el-input--medium .el-input__inner {
  599. width: 105px;
  600. }
  601. }
  602. .line {
  603. text-align: center;
  604. }
  605. .btns {
  606. height: 36px;
  607. display: flex;
  608. align-items: center;
  609. i {
  610. font-size: 24px;
  611. cursor: pointer;
  612. margin-left: 5px;
  613. }
  614. }
  615. .bop-tip {
  616. background: #fff6f7;
  617. margin: 0 0 20px 10px;
  618. padding: 8px 10px;
  619. i {
  620. font-size: 16px;
  621. color: #e6a23c;
  622. }
  623. }
  624. </style>