area-three-sidebar-template.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // 传入你要获取的参数的名字
  2. function getParam (name) {
  3. var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
  4. var r = window.location.search.substr(1).match(reg); //获取url中'?'符后的字符串并正则匹配
  5. var context = '';
  6. if (r != null) context = r[2];
  7. // 释放变量
  8. reg = null;
  9. r = null;
  10. return context == null || context == '' || context == 'undefined' ? '' : context;
  11. }
  12. // 需要结合area-three-sidebar-template.js使用
  13. function getRandomString (len) {
  14. let randomString = ''
  15. if (len) {
  16. var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
  17. var maxPos = $chars.length
  18. for (let i = 0; i < len; i++) {
  19. randomString += $chars.charAt(Math.floor(Math.random() * maxPos))
  20. }
  21. } else {
  22. randomString = Math.random().toString(36).substring(2)
  23. }
  24. return randomString
  25. }
  26. var AreaThreeSidebarTemplate = `
  27. <sidebar-selector-ui
  28. ref="firstSidebar"
  29. class="area-city-sidebar-selector first-sidebar"
  30. :height="height"
  31. :class="{
  32. 'disabled-city': disabledCitySelect,
  33. 'province-city-split': useProvinceCitySplit
  34. }"
  35. :whenParentLevel0Selected="whenParentLevel0Selected"
  36. :sourceList="provinceList"
  37. :childrenAddText="childrenAddText"
  38. @onChange="onChangeFirst"
  39. :beforeChildChange="beforeChildChange"
  40. :showParentWhenChildrenEmpty="false"
  41. :lazyRender="false">
  42. <template #tab-tag="{ parent }">
  43. <slot name="tab-tag" :parent="parent">
  44. <van-tag
  45. round
  46. type="primary"
  47. v-if="parent.value && sourceFirstCount[parent.value] && sourceFirstCount[parent.value]._children_selectedCount"
  48. :class="{ visible: sourceFirstCount[parent.value]._children_selectedCount === 0 }">
  49. {{sourceFirstCount[parent.value]._children_selectedCount }}
  50. </van-tag>
  51. </slot>
  52. </template>
  53. <template #tab-content="{ parent }">
  54. <!-- 嵌套的 side-bar 组件 -->
  55. <Sidebar-selector-ui
  56. :ref="'secondSidebar_' + parent.id || ''"
  57. class="area-city-sidebar-selector second-sidebar"
  58. :class="{
  59. 'disabled-city': disabledCitySelect,
  60. 'province-city-split': useProvinceCitySplit
  61. }"
  62. :height="height"
  63. :childrenAddText="childrenAddText"
  64. :source-list="parent.children"
  65. @onChange="onChange($event, parent.value)"
  66. :beforeChildChange="beforeChildChange"
  67. :showParentWhenChildrenEmpty="false">
  68. <template #tab-item="{ parent }">
  69. <div class="title-name" v-show="!isGAT(parent.name)">{{ parent.name }}</div>
  70. <div class="title-text" v-show="!isGAT(parent.name)">
  71. <slot name="tab-tag" :parent="parent">
  72. <van-tag
  73. round
  74. type="primary"
  75. v-if="tagTextOnlySelectedCount && parent._children_selectedCount">
  76. {{ parent._children_selectedCount }}
  77. </van-tag>
  78. </slot>
  79. </div>
  80. </template>
  81. <template #default="{ parent, child }">
  82. <slot name="default" v-bind="{ parent, child }">
  83. <template v-if="parent.level !== 0 && child.level === 0 && useProvinceCitySplit">
  84. <van-cell is-link :border="false">
  85. {{child.name}}
  86. <template #right-icon>
  87. <span class="j-icon checkbox" :class="{ checked: child._selected }"></span>
  88. </template>
  89. </van-cell>
  90. <div class="children-title border-line-b" @click.stop>
  91. <div class="c-title-text">市级</div>
  92. <van-tag v-if="disabledCitySelect" round plain type="danger" @click="disabledCityClick">开通</van-tag>
  93. </div>
  94. </template>
  95. </slot>
  96. </template>
  97. </Sidebar-selector-ui>
  98. </template>
  99. </sidebar-selector-ui>`
  100. var areaThreeSidebarComponent = {
  101. name: 'area-three-sidebar-template',
  102. template: AreaThreeSidebarTemplate,
  103. components: {
  104. SidebarSelectorUi: SidebarSelectorUi
  105. },
  106. props: {
  107. height: {
  108. type: String,
  109. default: ''
  110. },
  111. value: {
  112. type: Object,
  113. default () {
  114. return {}
  115. }
  116. },
  117. /**
  118. * 省份城市布局分割
  119. */
  120. useProvinceCitySplit: {
  121. type: Boolean,
  122. default: false
  123. },
  124. /**
  125. * 城市选择禁用
  126. */
  127. disabledCitySelect: {
  128. type: Boolean,
  129. default: false
  130. },
  131. /**
  132. * 数据统计tag显示
  133. */
  134. tagTextOnlySelectedCount: {
  135. type: Boolean,
  136. default: false
  137. },
  138. /**
  139. * 二级子项 "全部" 文字的替换
  140. */
  141. childrenAddText: String,
  142. /**
  143. * 更改确认函数
  144. *
  145. * 如果传入该函数,点击二级子项会触发,返回true会确认成功,返回false则会阻止更改
  146. */
  147. beforeChange: Function,
  148. /**
  149. * 是否可全不选中
  150. */
  151. canEmptySelected: {
  152. type: Boolean,
  153. default: false
  154. }
  155. },
  156. model: {
  157. prop: 'value',
  158. event: 'modelChange'
  159. },
  160. watch: {
  161. value: {
  162. handler(newVal) {
  163. this.setState(newVal)
  164. },
  165. deep: true
  166. }
  167. },
  168. data () {
  169. return {
  170. // 原始数组
  171. provinceListMapExp: {
  172. '#': ['全国'],
  173. A: ['安徽', '澳门'],
  174. B: ['北京'],
  175. C: ['重庆'],
  176. F: ['福建'],
  177. G: ['广东', '广西', '贵州', '甘肃'],
  178. H: ['河北', '湖北', '黑龙江', '海南', '河南', '湖南'],
  179. J: ['吉林', '江苏', '江西'],
  180. L: ['辽宁'],
  181. N: ['内蒙古', '宁夏'],
  182. Q: ['青海'],
  183. S: ['山西', '陕西', '上海', '山东', '四川'],
  184. T: ['天津', '台湾'],
  185. X: ['西藏', '新疆', '香港'],
  186. Y: ['云南'],
  187. Z: ['浙江']
  188. },
  189. whenParentLevel0Selected: false,
  190. // 原始城市数据
  191. // chinaMapJSON,
  192. provinceListMap: {
  193. // A: [
  194. // {
  195. // name: '安徽',
  196. // expanded: false,
  197. // canExpanded: true,
  198. // selectedState: '',
  199. // children: []
  200. // }
  201. // ]
  202. },
  203. provinceList: [],
  204. // indexBar数据
  205. indexList: [],
  206. provinceExp: {
  207. name: '安徽',
  208. value: '',
  209. // 展开状态
  210. expanded: false,
  211. // 是否可以展开
  212. canExpanded: false,
  213. children: []
  214. },
  215. sourceFirstCount: {},
  216. // 全国二级菜单名
  217. allCountryRefName: null,
  218. // 二级菜单ref名
  219. secondRefNameObj: {}
  220. }
  221. },
  222. created () {
  223. this.init(this.provinceListMapExp)
  224. },
  225. mounted () {
  226. var defaultVal = this.canEmptySelected ? -1 : {}
  227. this.setState(defaultVal)
  228. this.setActiveTab(1)
  229. },
  230. methods: {
  231. setActiveTab (num) {
  232. var { firstSidebar } = this.$refs
  233. firstSidebar.setActiveTab(num)
  234. },
  235. // 整理城市数据列表(并初始化indexBar数据)
  236. init (provinceListMapExp) {
  237. // 整理数据得到List,同时获得indexList
  238. var provinceListMap = {}
  239. var indexList = []
  240. this.secondRefNameObj = {}
  241. this.allCountryRefName = null
  242. for (var key in provinceListMapExp) {
  243. var areaArr = []
  244. indexList.push(key)
  245. provinceListMapExp[key].forEach(pName => {
  246. var provinceExp = JSON.parse(JSON.stringify(this.provinceExp))
  247. provinceExp.name = pName
  248. provinceExp.id = `ap-${getRandomString(8).toLowerCase()}`
  249. // 记录下二级ref
  250. this.$set(this.secondRefNameObj, pName, 'secondSidebar_' + provinceExp.id)
  251. if(pName === '全国') {
  252. this.allCountryRefName = 'secondSidebar_' + provinceExp.id
  253. }
  254. if (pName !== '全国') {
  255. var cities = this.getCitiesFromJSONMap(pName)
  256. // 筛选掉直辖市和特别行政区(台湾省也不不需要展开)
  257. if (cities.ProRemark === '省份' || cities.ProRemark === '自治区') {
  258. if (cities.ProID === 32) {
  259. provinceExp.children = []
  260. provinceExp.canExpanded = false
  261. } else {
  262. cities.city.forEach(c => {
  263. // 将区县数据取出,处理成新数组,放入城市
  264. let districtChildren = []
  265. if(c.area && c.area.length > 0) {
  266. districtChildren = c.area.map(dItem => {
  267. return {
  268. district: dItem,
  269. selected: false,
  270. canSelected: true,
  271. id: `adi-${getRandomString(8).toLowerCase()}`
  272. }
  273. })
  274. }
  275. // 将市区重组成一个新的对象
  276. provinceExp.children.push({
  277. city: c.name,
  278. selected: false,
  279. canSelected: true,
  280. id: `ac-${getRandomString(8).toLowerCase()}`,
  281. children: districtChildren// 区县
  282. })
  283. })
  284. }
  285. } else if (cities.ProRemark === '直辖市') {
  286. // 直辖市,将区县放置到第二级
  287. if(cities.city && Array.isArray(cities?.city)) {
  288. var orgDistrict = cities?.city[0].area || []
  289. // 将区县数据取出,处理成新数组,放入城市
  290. let districtChildren = orgDistrict.map(dItem => {
  291. return {
  292. district: dItem,
  293. selected: false,
  294. canSelected: true,
  295. id: `adi-${getRandomString(8).toLowerCase()}`
  296. }
  297. })
  298. provinceExp.children.push({
  299. city: provinceExp.name?.indexOf('市') > -1 ? provinceExp.name : provinceExp.name + '市',
  300. selected: false,
  301. canSelected: true,
  302. id: `ac-${getRandomString(8).toLowerCase()}`,
  303. children: districtChildren
  304. })
  305. }
  306. } else {
  307. provinceExp.children = []
  308. provinceExp.canExpanded = false
  309. }
  310. }
  311. provinceExp.canExpanded = provinceExp.children.length !== 0
  312. areaArr.push(provinceExp)
  313. })
  314. provinceListMap[key] = areaArr
  315. }
  316. this.provinceListMap = provinceListMap
  317. this.indexList = indexList.filter(i => i !== '#')
  318. // 给provinceListMap赋值
  319. for (var k in provinceListMap) {
  320. this.$set(this.provinceListMap, k, provinceListMap[k])
  321. }
  322. this.initProvinceList(provinceListMap)
  323. },
  324. // 循环chinaMapJSON,找到对应省下面对应的市
  325. getCitiesFromJSONMap (provinceName) {
  326. let temp = null
  327. for (let i = 0; i < chinaMapJSON.length; i++) {
  328. var findThis = chinaMapJSON[i].name.indexOf(provinceName) !== -1
  329. // 如果找到了,就不再循环后面的了
  330. if (findThis) {
  331. temp = chinaMapJSON[i]
  332. break
  333. }
  334. }
  335. return temp
  336. },
  337. initProvinceList (provinceListMap) {
  338. var provinceList = []
  339. for (var key in provinceListMap) {
  340. var provinces = provinceListMap[key]
  341. provinces.forEach(province => {
  342. if (province.name === '全国') {
  343. province.level = 0
  344. } else {
  345. province.level = 1
  346. }
  347. var cities = []
  348. if (Array.isArray(province.children)) {
  349. province.children.forEach(city => {
  350. // 将区县数据取出,处理成新数组,放入城市
  351. let districtChildren = []
  352. if(Array.isArray(city.children)) {
  353. districtChildren = city.children.map(dItem => {
  354. return {
  355. topName: province.name,
  356. parentName: city.city,
  357. name: dItem.district,
  358. value: dItem.district,
  359. id: dItem.id,
  360. level: 3
  361. }
  362. })
  363. }
  364. cities.push({
  365. id: city.id,
  366. name: city.city,
  367. value: city.city,
  368. level: 2,
  369. parentName: province.name,
  370. sourceChildrenCount: districtChildren.length, // 子集真实数量
  371. children: districtChildren // 区县
  372. })
  373. })
  374. }
  375. provinceList.push({
  376. id: province.id,
  377. name: province.name,
  378. value: province.name,
  379. level: province.level,
  380. sourceChildrenCount: cities.length, // 子集真实数量
  381. children: cities,
  382. hasThree: true
  383. })
  384. })
  385. }
  386. this.provinceList = provinceList
  387. },
  388. disabledCityClick () {
  389. this.$emit('on-disabled-city-click')
  390. },
  391. beforeChildChange (parent, child) {
  392. if (this.beforeChange) {
  393. return this.beforeChange(parent, child)
  394. }
  395. // 已选的省份列表
  396. const selectedProvinceList = []
  397. for(var key in this.sourceFirstCount) {
  398. selectedProvinceList.push(key)
  399. }
  400. if (this.disabledCitySelect) {
  401. if(parent.parentName && selectedProvinceList.indexOf(parent.parentName) > -1) {
  402. return true
  403. } else {
  404. this.disabledCityClick()
  405. return false
  406. }
  407. } else {
  408. return true
  409. }
  410. },
  411. getState () {
  412. var { state } = this.getStateMore()
  413. return state
  414. },
  415. /**
  416. * 最后输出数据结构
  417. * 参数area示例
  418. * {
  419. * 澳门: {}
  420. * 北京: {
  421. * 北京: ['朝阳区']
  422. * },
  423. * 河南: {
  424. * 南阳市: [],
  425. * 郑州: ['金水区'],
  426. * 洛阳市: ['栾川县','老城区']
  427. * }
  428. * }
  429. */
  430. getStateMore () {
  431. // 选中状态
  432. var state = {}
  433. // 选中数量统计
  434. var stateCounter = {}
  435. // 是否选了全国
  436. var isSelectedCountry = false
  437. // 所有二级市区遍历
  438. for(let refKey in this.secondRefNameObj) {
  439. var refName = this.secondRefNameObj[refKey]
  440. var renderList = this.$refs[refName]?.renderList || []
  441. for (let i = 0; i < renderList.length; i++) {
  442. var parent = renderList[i]
  443. var children = parent.children
  444. var provinceName = parent.parentName
  445. // 全国选中
  446. if (parent.level === 0 && provinceName === '全国') {
  447. if (children && children[0]._selected) {
  448. isSelectedCountry = true
  449. break
  450. }
  451. continue
  452. }
  453. // 当前省份下,全部选中(保存当前省份)
  454. if(parent.level === 0 && provinceName !== '全国') {
  455. // 市区【全部】和区县【全部】都选中
  456. if (parent._selected) {
  457. state[provinceName] = {}
  458. break
  459. }
  460. continue
  461. }
  462. // 当前市全选中(【市区】和【全部】选中)
  463. if(parent.level === 2 && parent._selected) {
  464. if(!state[provinceName]) {
  465. state[provinceName] = {}
  466. }
  467. this.$set(state[provinceName], parent.name, [])
  468. continue
  469. }
  470. // 区县选择
  471. if (Array.isArray(children)) {
  472. var childSelected = []
  473. for (let j = 0; j < children.length; j++) {
  474. var child = children[j]
  475. if (child.level === 0) {
  476. continue
  477. } else {
  478. if (child._selected) {
  479. childSelected.push(child.value)
  480. }
  481. }
  482. }
  483. if (childSelected.length > 0) {
  484. if(!state[provinceName]) {
  485. state[provinceName] = {}
  486. }
  487. if(!state[provinceName][parent.name]) {
  488. this.$set(state[provinceName], parent.name, [])
  489. }
  490. state[provinceName][parent.name] = childSelected
  491. }
  492. }
  493. }
  494. }
  495. var resultState = state
  496. if(Object.keys(state).length === 0 && !isSelectedCountry && this.canEmptySelected) {
  497. resultState = -1
  498. }
  499. return {
  500. state: resultState,
  501. stateCounter
  502. }
  503. },
  504. /**
  505. * 设置组件状态
  506. * getState中获取的数据能够直接传入进行状态恢复
  507. * 全部不选中传入-1
  508. */
  509. setState (state) {
  510. // 所有都不选中
  511. if (state === -1) {
  512. this.resetSelect(false)
  513. this.$emit('modelChange', -1)
  514. return
  515. }
  516. var firstSidebar = this.$refs.firstSidebar
  517. firstSidebar.setAllState(false)
  518. firstSidebar.refreshAllChildrenState(false)
  519. // 重置第二级,并且选中全国
  520. this.resetSelect()
  521. if (typeof state === 'object' && Object.keys(state).length > 0) {
  522. this.setSidebarState(state)
  523. this.$refs[this.allCountryRefName]?.setParentLevel0State(false)
  524. }
  525. // 重新计算parent数据统计
  526. firstSidebar.refreshAllChildrenState()
  527. this.$emit('modelChange', state || {})
  528. },
  529. setSidebarState (state) {
  530. for(var proName in state) {
  531. var refName = this.secondRefNameObj[proName]
  532. var refItem = this.$refs[refName]
  533. if(!refItem) {
  534. return
  535. }
  536. // 选择了全省
  537. var stateProvince = state[proName]
  538. // 第一级省份下选中的市区数量
  539. let _children_selectedCount = 0
  540. refItem.setState(renderList => {
  541. // 选择了全省
  542. if(stateProvince && Object.keys(stateProvince).length === 0) {
  543. refItem.setAllState(true)
  544. refItem.refreshAllChildrenState(true)
  545. // 更新第一级 side-bar 的状态
  546. _children_selectedCount = renderList.length - 1
  547. } else {
  548. renderList.forEach(parent => {
  549. // 当前市下选择的区域数组
  550. var stateDistrict = stateProvince[parent.name]
  551. if(stateDistrict) {
  552. if (Array.isArray(stateDistrict)) {
  553. _children_selectedCount += 1
  554. // 选择了全市
  555. if (stateDistrict.length === 0) {
  556. refItem.setChildrenState(parent.children, true)
  557. } else {
  558. // 选择了部分区域
  559. parent.children.forEach(child => {
  560. if (stateDistrict.includes(child.value)) {
  561. child._selected = true
  562. }
  563. })
  564. }
  565. }
  566. refItem.checkChildrenAllChecked(parent, parent.children)
  567. }
  568. })
  569. }
  570. // 更新第一级 side-bar 的状态
  571. this.$set(this.sourceFirstCount, proName, {
  572. _children_selectedCount: _children_selectedCount,
  573. _children_count: renderList.length - 1
  574. })
  575. })
  576. refItem.refreshAllChildrenState()
  577. }
  578. },
  579. // 重置所有选择
  580. resetSelect(selectedAll = true) {
  581. var { firstSidebar } = this.$refs
  582. firstSidebar.setAllState(false)
  583. firstSidebar.refreshAllChildrenState(false)
  584. firstSidebar.setParentLevel0State(selectedAll)
  585. var firstRenderList = firstSidebar.renderList
  586. for(let item of firstRenderList) {
  587. var secondRef = this.$refs['secondSidebar_' + item.id]
  588. secondRef.setAllState(false)
  589. secondRef.refreshAllChildrenState(false)
  590. if(item.name === '全国'){
  591. secondRef.setParentLevel0State(selectedAll)
  592. }
  593. }
  594. this.sourceFirstCount = {}
  595. },
  596. // 处理第一级 side-bar 组件的变化事件
  597. onChangeFirst({ parent, child, renderList }) {
  598. if (parent.level === 0 && parent.name === '全国') {
  599. this.resetSelect()
  600. } else {
  601. this.$set(this.sourceFirstCount, parent.value, {
  602. _children_selectedCount: parent._children_selectedCount,
  603. _children_count: parent._children_count
  604. })
  605. this.$refs.firstSidebar.setParentLevel0State(false)
  606. }
  607. },
  608. // 处理第二级 side-bar 组件的变化事件
  609. onChange ({ parent, child, renderList }, value) {
  610. this.disposeSecondCount({ parent, child, renderList }, value)
  611. var stateValue = this.getState()
  612. var payload = { parent, child, value: stateValue }
  613. this.$emit('modelChange', payload.value)
  614. this.$emit('change', payload)
  615. },
  616. // 处理二级菜单选择
  617. disposeSecondCount ({ parent, child, renderList }, value) {
  618. if(parent.level === 0 && parent.parentName ==='全国'){
  619. this.resetSelect()
  620. return
  621. }
  622. // 将全国选择重置掉
  623. if(this.allCountryRefName) {
  624. this.$refs[this.allCountryRefName]?.setParentLevel0State(false)
  625. }
  626. var selectedNum = renderList?.filter(temp => temp._children_selectedCount > 0)?.length || 0
  627. var result = {
  628. _children_selectedCount: selectedNum,
  629. _children_count: renderList.length - 1
  630. }
  631. // 更新第一级 side-bar 的状态
  632. this.$set(this.sourceFirstCount, value, result)
  633. this.$refs.firstSidebar.setParentLevel0State(false)
  634. },
  635. // 是否是港澳台地区
  636. isGAT(val) {
  637. var GATList = ['香港', '澳门', '台湾']
  638. return val && GATList.indexOf(val) > -1
  639. }
  640. }
  641. }