FreeSubConfig.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. <template>
  2. <div class="free-subscribe-container">
  3. <div class="sub-content">
  4. <div class="item">
  5. <div class="item-label item-label-required">区域:</div>
  6. <div
  7. class="item-value"
  8. v-loading="!setStatus"
  9. element-loading-custom-class="prevent-loading"
  10. >
  11. <AreaCityCountryCascader
  12. ref="areaCityCountry"
  13. showSelected
  14. showCount
  15. stopDropdown
  16. :showCity="false"
  17. :showCountry="false"
  18. :areaCount="maxSelectAreaCount"
  19. :initMap="areaData"
  20. @hideSelect="onAreaHideSelect"
  21. @onClick="onAreaSelectClick"
  22. @change="onAreaCityCountryChange"
  23. @exceed="onExceedChange"
  24. >
  25. <div slot="header"></div>
  26. </AreaCityCountryCascader>
  27. </div>
  28. </div>
  29. <div class="item">
  30. <div class="item-label item-label-required">信息类型:</div>
  31. <div
  32. class="item-value"
  33. @click="dialog.infoType = true"
  34. v-loading="!setStatus"
  35. element-loading-custom-class="prevent-loading"
  36. >
  37. <el-input
  38. class="custom-long-input"
  39. v-model="datas.infoTypeStr"
  40. readonly
  41. unselectable="on"
  42. ></el-input>
  43. </div>
  44. </div>
  45. <div class="item">
  46. <div class="item-label">关键词匹配方式:</div>
  47. <div
  48. class="item-value"
  49. v-loading="!setStatus"
  50. element-loading-custom-class="prevent-loading"
  51. >
  52. <CheckboxGroupSelector
  53. :sourceList="keywordMatchTypeList"
  54. keepOne
  55. @change="onMatchTypeChange"
  56. v-model="datas.matchType"
  57. ></CheckboxGroupSelector>
  58. </div>
  59. </div>
  60. </div>
  61. <!-- 区域选择dialog -->
  62. <el-dialog
  63. custom-class="sub-dialog"
  64. :visible.sync="dialog.area"
  65. :close-on-click-modal="false"
  66. :show-close="false"
  67. center
  68. width="460px"
  69. >
  70. <AreaSelect
  71. :initCityMap="datas.areaObj"
  72. @onCancel="dialog.area = false"
  73. @onConfirm="saveAreaData"
  74. :showSelectResult="true"
  75. :showSelectedDetail="false"
  76. :areaCount="maxSelectAreaCount"
  77. >
  78. <template #update-tips
  79. >超出已购买省份数量,请联系客户成功经理进行升级</template
  80. >
  81. </AreaSelect>
  82. </el-dialog>
  83. <!-- 采购单位行业dialog -->
  84. <el-dialog
  85. custom-class="sub-dialog"
  86. :visible.sync="dialog.buyClass"
  87. :close-on-click-modal="false"
  88. :show-close="false"
  89. center
  90. width="460px"
  91. >
  92. <BuyClassSelect
  93. :initCate="datas.buyClassArr"
  94. :otherMatch="datas.buyclassmatch"
  95. @onCancel="dialog.buyClass = false"
  96. @onConfirm="saveBuyClassData"
  97. @onOtherConfirm="saveOtherBuyClass"
  98. >
  99. <div slot="header">选择采购单位类型</div>
  100. </BuyClassSelect>
  101. </el-dialog>
  102. <!-- 信息类型dialog -->
  103. <el-dialog
  104. custom-class="sub-dialog info-type-dialog"
  105. :visible.sync="dialog.infoType"
  106. :close-on-click-modal="false"
  107. :show-close="false"
  108. center
  109. width="460px"
  110. >
  111. <InfoTypeSelect
  112. :initInfoType="datas.infoTypeArr"
  113. showDataType="oneLevel"
  114. @onCancel="dialog.infoType = false"
  115. @onConfirm="saveInfoTypeData"
  116. >
  117. <div slot="header">选择信息类型</div>
  118. </InfoTypeSelect>
  119. </el-dialog>
  120. <el-dialog
  121. :visible.sync="dialog.areaMap"
  122. title="超出可选省份数量"
  123. :show-close="false"
  124. class="tip-dialog"
  125. width="380px"
  126. top="30vh"
  127. center
  128. >
  129. <div>
  130. 可选:<span class="highlight-text">{{ maxSelectAreaCount }}个省</span
  131. >,如需增加省份数量,您可联系客服升级大会员。
  132. </div>
  133. <div slot="footer" class="dialog-footer">
  134. <el-button type="primary" @click.stop="goConcatCustomer"
  135. >联系客服</el-button
  136. >
  137. <el-button @click="dialog.areaMap = false">取 消</el-button>
  138. </div>
  139. </el-dialog>
  140. <popupBox
  141. ref="popupBox"
  142. text="如需修改区域,请联系企业管理员修改分发设置区域。"
  143. title="不支持修改区域"
  144. ></popupBox>
  145. </div>
  146. </template>
  147. <script>
  148. import {
  149. Switch,
  150. Input,
  151. RadioGroup,
  152. Radio,
  153. Button,
  154. Dialog,
  155. Checkbox
  156. } from 'element-ui'
  157. import AreaSelect from '@/components/selector/AreaSelector'
  158. import BuyClassSelect from '@/components/selector/BuyerclassSelector'
  159. import InfoTypeSelect from '@/components/selector/InfoTypeSelector'
  160. import popupBox from '@/components/common/popupBox'
  161. import AreaCityCountryCascader from '@/components/selector-cascader/AreaCityCountryCascader'
  162. import CheckboxGroupSelector from '@/components/selector/CheckboxGroupSelector'
  163. import { keywordMatchTypeListOfFree } from '@/assets/js/selector.js'
  164. import AmountRangeSelector from '@/components/selector/AmountRangeSelector.vue'
  165. import {
  166. setAreaBuyer,
  167. setUserInfoVip,
  168. userRule,
  169. entBaseInfo
  170. } from '@/api/modules'
  171. export default {
  172. name: 'free-sub-config',
  173. props: {
  174. datas: {
  175. areaStr: String,
  176. buyClassStr: String,
  177. infoTypeStr: String,
  178. projectmatch: Number,
  179. buyclassmatch: Number,
  180. mathway: Number,
  181. areaObj: Object,
  182. areaCount: Number, // 用户购买了几个省份(单省版本)
  183. buyClassArr: Array,
  184. infoTypeArr: Array,
  185. matchType: Array,
  186. amount: String
  187. },
  188. // 订阅设置开关
  189. setStatus: {
  190. type: Boolean,
  191. default: false
  192. },
  193. canSelect: {
  194. type: Boolean,
  195. default: true
  196. }
  197. },
  198. components: {
  199. [Switch.name]: Switch,
  200. [Input.name]: Input,
  201. [RadioGroup.name]: RadioGroup,
  202. [Radio.name]: Radio,
  203. [Button.name]: Button,
  204. [Dialog.name]: Dialog,
  205. AreaSelect,
  206. BuyClassSelect,
  207. InfoTypeSelect,
  208. popupBox,
  209. AreaCityCountryCascader,
  210. CheckboxGroupSelector,
  211. AmountRangeSelector
  212. },
  213. data() {
  214. return {
  215. projectSwitch: {
  216. loading: false,
  217. disabled: false
  218. },
  219. unitSwitch: {
  220. loading: false,
  221. disabled: false
  222. },
  223. dialog: {
  224. area: false,
  225. buyClass: false,
  226. infoType: false,
  227. areaMap: false
  228. },
  229. areaData: {},
  230. buyerData: [],
  231. timeout: null,
  232. isSetArea: false,
  233. keywordMatchTypeList: keywordMatchTypeListOfFree,
  234. switchMode: this.setStatus
  235. }
  236. },
  237. computed: {
  238. // -1表示可选范围为全国
  239. maxSelectAreaCount() {
  240. const { areaCount } = this.datas
  241. return areaCount || -1
  242. },
  243. formatAreaMap() {
  244. const original = this.areaData
  245. // if (!original) return ''
  246. // 原二级数据结构为{福建:['福州', '厦门', '宁德']}
  247. // 现数据结构为三级 需进行处理
  248. if (Object.keys(original).length > 0) {
  249. const obj = {}
  250. for (const province in original) {
  251. let cityMap = {}
  252. if (Array.isArray(original[province])) {
  253. original[province].forEach((city) => {
  254. cityMap[city] = []
  255. })
  256. } else {
  257. cityMap = original[province]
  258. }
  259. obj[province] = cityMap
  260. }
  261. return obj
  262. } else {
  263. return original
  264. }
  265. }
  266. },
  267. watch: {
  268. 'datas.areaObj'(newVal) {
  269. this.areaData = newVal
  270. try {
  271. this.$refs.areaCityCountry.setState('')
  272. this.$refs.areaCityCountry.setState(newVal)
  273. } catch (error) {}
  274. },
  275. 'datas.buyClassArr'(newVal) {
  276. this.buyerData = newVal
  277. }
  278. },
  279. mounted() {},
  280. methods: {
  281. onAmountRangeChange(amount) {
  282. const { value } = amount
  283. this.commonSetApi({
  284. pageType: 'amount',
  285. matchtype: value
  286. })
  287. },
  288. // 关键词匹配方式选择结果回调(新)
  289. onMatchTypeChange(data) {
  290. this.commonSetApi({
  291. pageType: 'matchmode',
  292. matchtype: data.toString()
  293. })
  294. },
  295. debounce(fn, delay) {
  296. if (this.timeout) {
  297. clearTimeout(this.timeout)
  298. }
  299. this.timeout = setTimeout(() => {
  300. fn()
  301. }, delay)
  302. },
  303. clickErea() {
  304. this.debounce(() => {
  305. entBaseInfo({}).then((res) => {
  306. if (
  307. res.data.vip_power === 1 ||
  308. res.data.member_power === 1 ||
  309. res.data.user_power === 1
  310. ) {
  311. // 企业授权
  312. userRule().then((res_) => {
  313. if (res_.data) {
  314. // 设置了区域
  315. this.$refs.popupBox.isshow = true
  316. } else {
  317. this.dialog.area = true
  318. }
  319. })
  320. } else {
  321. // 非企业授权
  322. this.dialog.area = true
  323. }
  324. })
  325. }, 200)
  326. },
  327. // 切换项目匹配按钮
  328. switchProjectMatch(event) {
  329. this.projectSwitch.loading = true
  330. this.projectSwitch.disabled = true
  331. this.commonSetApi(
  332. {
  333. pageType: 'projectMatch',
  334. pmindex: event
  335. },
  336. () => {
  337. this.projectSwitch.loading = false
  338. this.projectSwitch.disabled = false
  339. this.$message({
  340. message: event === 1 ? '项目匹配已开启' : '项目匹配已关闭',
  341. type: 'success'
  342. })
  343. }
  344. )
  345. },
  346. // 原关键词匹配方式(弃用)
  347. async chooseMathWay(state) {
  348. this.commonSetApi({
  349. pageType: 'saveSeniorset',
  350. matchtype: state
  351. })
  352. },
  353. // 保存区域修改数据(已停用)
  354. saveAreaData(data) {
  355. setAreaBuyer({
  356. vSwitch: 'm',
  357. area: JSON.stringify(data),
  358. industry: this.buyerData.toString()
  359. }).then((res) => {
  360. if (res.data.doSuccess) {
  361. this.$emit('update')
  362. this.dialog.area = false
  363. } else {
  364. this.$message({
  365. message: '修改失败',
  366. type: 'error'
  367. })
  368. }
  369. })
  370. },
  371. // 保存采购单位行业数据及匹配未分类行业数据
  372. saveBuyClassData(data) {
  373. const { area, district } =
  374. this.$refs.areaCityCountry.formatProvinceAndCities(this.areaData)
  375. setAreaBuyer({
  376. vSwitch: 'm',
  377. // area: JSON.stringify(this.areaData),
  378. area: JSON.stringify(area),
  379. district: JSON.stringify(district),
  380. industry: data.toString()
  381. }).then((res) => {
  382. if (res.data.doSuccess) {
  383. this.$emit('update')
  384. this.dialog.buyClass = false
  385. } else {
  386. this.$message({
  387. message: '修改失败',
  388. type: 'error'
  389. })
  390. }
  391. })
  392. },
  393. // 保存未匹配采购单位行业
  394. saveOtherBuyClass(data) {
  395. this.commonSetApi({
  396. pageType: 'other_buyerclass',
  397. other: data.selected ? 1 : 0
  398. })
  399. },
  400. // 保存信息类型数据
  401. saveInfoTypeData(data) {
  402. this.commonSetApi(
  403. {
  404. pageType: 'infoType',
  405. infoTypeArr: data.toString(),
  406. vSwitch: 'f'
  407. },
  408. () => {
  409. this.dialog.infoType = false
  410. }
  411. )
  412. },
  413. // 设置接口
  414. commonSetApi(data, callback) {
  415. setUserInfoVip(data).then((res) => {
  416. if (res.flag) {
  417. this.$emit('update')
  418. callback && callback()
  419. } else {
  420. this.$message({
  421. message: '修改失败',
  422. type: 'error'
  423. })
  424. }
  425. })
  426. },
  427. // 组件选择地区回调事件(场景:每次选择都需保存)
  428. onAreaCityCountryChange(data) {
  429. const { area, district } = data
  430. console.log(area, district)
  431. },
  432. async onAreaSelectClick() {
  433. if (!this.canSelect) {
  434. return this.$message({
  435. message: '修改区域次数已达上限',
  436. type: 'error'
  437. })
  438. }
  439. this.$refs.areaCityCountry.toggleSelect()
  440. return false
  441. const { data } = await entBaseInfo()
  442. if (
  443. data.vip_power === 1 ||
  444. data.member_power === 1 ||
  445. data.user_power === 1
  446. ) {
  447. // 企业授权
  448. const { data: flag } = await userRule()
  449. if (flag) {
  450. this.$refs.popupBox.isshow = true
  451. } else {
  452. this.$refs.areaCityCountry.toggleSelect()
  453. }
  454. } else {
  455. this.$refs.areaCityCountry.toggleSelect()
  456. }
  457. },
  458. // 当下拉框隐藏时回调事件(应用场景:每次选择地区时不需要都调用接口,等所有选择完 下拉框隐藏时再调用)
  459. onAreaHideSelect(data) {
  460. const { area, district } = data
  461. if (!data.resultText) {
  462. this.$refs.areaCityCountry.doReset()
  463. return false
  464. }
  465. setAreaBuyer({
  466. vSwitch: 'f',
  467. area: JSON.stringify(area),
  468. industry: this.buyerData.toString(),
  469. district: JSON.stringify(district)
  470. }).then((res) => {
  471. if (res?.data?.doSuccess) {
  472. this.$emit('update')
  473. this.dialog.area = false
  474. } else {
  475. if (res.errMsg && res.errMsg.indexOf('已用完') > -1) {
  476. this.$refs.areaCityCountry.doReset()
  477. }
  478. this.$message({
  479. message: res.errMsg || '修改失败',
  480. type: 'error'
  481. })
  482. }
  483. })
  484. },
  485. // 区域选择超出冒泡事件
  486. onExceedChange() {
  487. this.$message({
  488. message: '超出可订阅省份数量',
  489. type: 'error'
  490. })
  491. // this.dialog.areaMap = true
  492. },
  493. goConcatCustomer() {
  494. this.contactCustomer(this)
  495. }
  496. }
  497. }
  498. </script>
  499. <style lang="scss" scoped>
  500. .free-subscribe-container {
  501. .sub-content {
  502. padding: 20px 0;
  503. }
  504. .item {
  505. display: flex;
  506. align-items: center;
  507. justify-content: center;
  508. margin-bottom: 10px;
  509. }
  510. .item-label {
  511. margin-right: 8px;
  512. min-width: 120px;
  513. height: 40px;
  514. color: #1d1d1d;
  515. font-size: 14px;
  516. line-height: 40px;
  517. text-align: right;
  518. }
  519. .item-label-required:before {
  520. content: '*';
  521. color: #f56c6c;
  522. margin-right: 2px;
  523. }
  524. .item-value {
  525. position: relative;
  526. width: 352px;
  527. .item-mask {
  528. position: absolute;
  529. top: 0;
  530. left: 0;
  531. bottom: 0;
  532. right: 0;
  533. z-index: 10000;
  534. }
  535. }
  536. .custom-long-input {
  537. width: 352px;
  538. }
  539. .item-other {
  540. display: flex;
  541. justify-content: center;
  542. margin-bottom: 10px;
  543. }
  544. .item-other-value {
  545. margin-top: 8px;
  546. }
  547. .math-tips {
  548. margin-top: 4px;
  549. font-size: 12px;
  550. color: #999999;
  551. line-height: 20px;
  552. }
  553. .radio-item {
  554. margin-bottom: 10px;
  555. }
  556. // element-ui样式修改
  557. ::v-deep {
  558. .custom-long-input .el-input__inner {
  559. font-size: 14px;
  560. color: #2cb7ca;
  561. white-space: nowrap;
  562. overflow: hidden;
  563. text-overflow: ellipsis;
  564. border-color: #ececec;
  565. }
  566. .el-loading-spinner .circular {
  567. width: 22px;
  568. height: 22px;
  569. }
  570. .el-loading-spinner {
  571. margin-top: -11px;
  572. }
  573. .el-input__inner {
  574. background: #fff;
  575. cursor: pointer;
  576. }
  577. .el-switch {
  578. position: relative;
  579. }
  580. .el-switch__label--left {
  581. position: absolute;
  582. left: 6px;
  583. top: 0;
  584. color: #fff;
  585. z-index: 9;
  586. font-size: 12px;
  587. }
  588. .el-switch__label--right {
  589. position: absolute;
  590. right: 6px;
  591. top: 0;
  592. color: #fff;
  593. z-index: 9;
  594. font-size: 12px;
  595. }
  596. .el-switch__label * {
  597. font-size: 12px;
  598. }
  599. .el-switch,
  600. .el-switch__core {
  601. height: 22px;
  602. line-height: 22px;
  603. }
  604. .el-switch__core:after {
  605. width: 18px;
  606. height: 18px;
  607. }
  608. .el-switch.is-checked .el-switch__core::after {
  609. margin-left: -18px !important;
  610. }
  611. .el-radio {
  612. color: #1d1d1d;
  613. font-size: 14px;
  614. }
  615. .el-radio__inner {
  616. width: 20px;
  617. height: 20px;
  618. }
  619. .el-radio__input.is-checked .el-radio__inner {
  620. border: 0;
  621. background: transparent;
  622. width: 20px;
  623. height: 20px;
  624. background: url('~@/assets/images/icon-checked.png') no-repeat center
  625. center;
  626. background-size: contain;
  627. }
  628. .el-radio__inner::after {
  629. background: transparent;
  630. }
  631. .el-radio__input.is-checked + .el-radio__label {
  632. color: #1d1d1d;
  633. }
  634. .el-radio__inner:hover {
  635. border-color: #ececec;
  636. }
  637. .select-region {
  638. left: 0 !important;
  639. }
  640. .s-header {
  641. display: none;
  642. }
  643. .el-select {
  644. width: 100%;
  645. .el-input__inner {
  646. height: 40px;
  647. line-height: 40px;
  648. }
  649. .select-prefix {
  650. height: 38px;
  651. line-height: 38px;
  652. }
  653. }
  654. .tip-dialog {
  655. .el-button--primary,
  656. .el-button--primary:hover,
  657. .el-button--primary:focus {
  658. width: 132px;
  659. height: 36px;
  660. margin-right: 52px;
  661. text-align: center;
  662. background: #2cb7ca;
  663. border-radius: 6px;
  664. font-style: 16px;
  665. color: #fff;
  666. border: 0;
  667. }
  668. .el-dialog {
  669. border-radius: 8px;
  670. }
  671. .el-dialog__header {
  672. padding: 32px 0 0;
  673. }
  674. .el-dialog__body {
  675. padding: 20px 32px 32px;
  676. color: #686868;
  677. font-size: 14px;
  678. line-height: 22px;
  679. text-align: center;
  680. }
  681. .el-dialog__body i {
  682. color: #2cb7ca;
  683. }
  684. .el-button {
  685. width: 132px;
  686. height: 36px;
  687. padding: 0;
  688. text-align: center;
  689. font-size: 16px;
  690. }
  691. .el-dialog__footer {
  692. padding: 0 0 32px;
  693. }
  694. }
  695. .el-select-dropdown.select-custom {
  696. left: 0 !important;
  697. }
  698. .module-container.province-container {
  699. width: 100%;
  700. .el-icon-arrow-right {
  701. display: none;
  702. }
  703. }
  704. }
  705. }
  706. </style>