index.vue 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. <template>
  2. <div class="list">
  3. <HeadMenu class="list-head">
  4. <div class="list-head-search">
  5. <div class="left-select __hover" @click.stop="ref_area.togglePopperVisible(true)">
  6. 搜索范围<SvgIcon name="arrow_1" rotate="90" size="14" color="var(--cus-text-color-3)"/>
  7. <el-cascader ref="ref_area" class="area-cascader" v-model="state.cascaderParams.value" :props="state.cascaderParams.props" :options="state.cascaderParams.options"/>
  8. </div>
  9. <el-input v-model="state.searchText" placeholder="请输入关键字进行查询" @keyup.enter="onSearch"/>
  10. <div class="right-icon __hover" @click="onSearch">
  11. <SvgIcon name="search_1" color="var(--cus-main-color)" size="40"/>
  12. </div>
  13. </div>
  14. </HeadMenu>
  15. <div class="count-percent" v-if="state.ws.countPercent < 100">
  16. <div class="bar-bg"><div class="bar-block" :style="{width: state.ws.countPercent + '%'}"/></div>
  17. 已加载{{state.ws.countPercent}}%
  18. </div>
  19. <div class="list-content" :style="{
  20. paddingTop: state.ws.countPercent == 100 ? '24px' : 0
  21. }">
  22. <div class="list-filter">
  23. <div class="label">检索条件:</div>
  24. <div class="value">
  25. <template v-if="isSelectAllCpt || !state.cascaderParams.value.length">
  26. <div class="filter-item">全部</div>
  27. </template>
  28. <template v-else>
  29. <template v-for="(item, index) in state.cascaderParams.value">
  30. <div class="filter-item">
  31. {{ WebStore.searchAreaTypeMap.get(item) }}
  32. <SvgIcon class="__hover" name="close_1" size="10" color="var(--cus-text-color-3)" @click="onDelFilter(index)"/>
  33. </div>
  34. </template>
  35. </template>
  36. </div>
  37. </div>
  38. <div class="list-tab">
  39. <template v-for="item in state.resultParams.tree">
  40. <div class="list-tab-item __hover" :class="{active: item.treeId === state.resultParams.activeTab}" @click="state.resultParams.activeTab = item.treeId" v-if="item.__count > 0">
  41. {{item.treeName}}<span class="total">({{ item.__count }})</span>
  42. </div>
  43. </template>
  44. </div>
  45. <div class="list-result" v-if="state.resultParams.activeTab">
  46. <div class="list-result-tree">
  47. <template v-for="item in state.resultParams.tree.filter(v => v.treeId === state.resultParams.activeTab)[0].children">
  48. <div class="list-result-tree-item" v-if="item.__count > 0">
  49. <div class="item-parent __hover" @click="item.__expend = !item.__expend">
  50. <SvgIcon class="flag" name="flag_1" color="var(--cus-main-color)"/>
  51. {{item.treeName}}
  52. <span class="total">({{item.__count}})</span>
  53. <SvgIcon class="expend" name="arrow_1" :rotate="item.__expend ? -90 : 90" color="var(--cus-text-color-4)"/>
  54. </div>
  55. <transition-group name="list" tag="div">
  56. <template v-if="item.__expend">
  57. <template v-for="son in item.children">
  58. <div class="item-son __hover" :class="{active: son.treeId === state.resultParams.activeIndex}" @click="state.resultParams.activeIndex = son.treeId" v-if="son.__count > 0">
  59. {{son.treeName}}<span class="total">({{son.__count}})</span>
  60. </div>
  61. </template>
  62. </template>
  63. </transition-group>
  64. </div>
  65. </template>
  66. </div>
  67. <div class="list-result-table">
  68. <div class="table-head">
  69. <div class="table-head-index">
  70. <SvgIcon class="flag" name="flag_1" color="var(--cus-main-color)"/>
  71. {{currentIndexCpt.treeName}}
  72. <span class="total">({{currentIndexCpt.__count}})</span>
  73. </div>
  74. <div class="table-head-infos">
  75. <div class="main">
  76. <img src="@/assets/images/web/wen-list_table-head-icon-1.png"/>
  77. <div class="one">
  78. <div>更新时间:</div>
  79. <div>{{ state.resultParams.indexConfig?.updateTime }}</div>
  80. <div>接入时间:</div>
  81. <div>{{ state.resultParams.indexConfig?.createTime }}</div>
  82. </div>
  83. <div>
  84. <div>共享方式:</div>
  85. <div>{{ state.resultParams.indexConfig?.shareMethod }}</div>
  86. <div>更新周期:</div>
  87. <div>{{ state.resultParams.indexConfig?.shareCycle }}</div>
  88. </div>
  89. </div>
  90. <div class="info">
  91. <div class="block">
  92. <img src="@/assets/images/web/wen-list_table-head-icon-2.png"/>
  93. <div class="text">
  94. <div class="text-title">数据共享来源</div>
  95. <div class="text-value"><CusEllipsis :value="state.resultParams.indexConfig?.dataSource"/></div>
  96. </div>
  97. </div>
  98. </div>
  99. <div class="info">
  100. <div class="block">
  101. <img src="@/assets/images/web/wen-list_table-head-icon-3.png"/>
  102. <div class="text">
  103. <div class="text-title">数据提供来源</div>
  104. <div class="text-value"><CusEllipsis :value="state.resultParams.indexConfig?.dataOffer"/></div>
  105. </div>
  106. </div>
  107. </div>
  108. <div class="info">
  109. <div class="block">
  110. <img src="@/assets/images/web/wen-list_table-head-icon-4.png"/>
  111. <div class="text">
  112. <div class="text-title">数据量</div>
  113. <div class="text-value"><CusEllipsis :value="(state.resultParams.indexConfig?.num || 0) + '条'"/></div>
  114. </div>
  115. </div>
  116. </div>
  117. </div>
  118. </div>
  119. <div class="table-switch" v-if="tableConfigCpt.hasCard">
  120. <div class="__hover" :class="{active: state.tableParams.model === 'list'}" @click="state.tableParams.model = 'list'">
  121. <SvgIcon name="list_1" size="16" :color="state.tableParams.model === 'list' ? '#ffffff' : 'var(--cus-text-color-3)'"/>
  122. </div>
  123. <div class="__hover" :class="{active: state.tableParams.model === 'card'}" @click="state.tableParams.model = 'card'">
  124. <SvgIcon name="card_1" size="16" :color="state.tableParams.model === 'card' ? '#ffffff' : 'var(--cus-text-color-3)'"/>
  125. </div>
  126. </div>
  127. <div class="table-content" v-loading="state.tableParams.loading">
  128. <div class="table-content-result" v-if="tableConfigCpt.listConfig?.length > 0">
  129. <div class="table-list" v-if="state.tableParams.model === 'list'">
  130. <template v-for="(item, index) in state.tableParams.data">
  131. <div class="list-item __hover">
  132. <div class="index">{{index + 1 + (state.tableParams.pageNum - 1) * state.tableParams.pageSize }}</div>
  133. <div class="cols" :style="{
  134. gridTemplateColumns: `repeat(${tableConfigCpt.listCol}, 1fr)`
  135. }">
  136. <template v-for="c in tableConfigCpt.listConfig">
  137. <div class="cols-item" :style="{
  138. gridColumn: `span ${c.col}`
  139. }">
  140. <div class="cols-item-label">{{c.key}}:</div>
  141. <div class="cols-item-value">
  142. <CusEllipsis :value="item[c.value]" :html="true"/>
  143. </div>
  144. </div>
  145. </template>
  146. </div>
  147. <!-- <div class="operation">-->
  148. <!-- <div class="__hover">-->
  149. <!-- <SvgIcon name="detail_1" color="var(&#45;&#45;cus-main-color)"/>详情-->
  150. <!-- </div>-->
  151. <!-- <div class="__hover">-->
  152. <!-- <SvgIcon name="archives_1" color="var(&#45;&#45;cus-main-color)"/>档案-->
  153. <!-- </div>-->
  154. <!-- </div>-->
  155. </div>
  156. </template>
  157. </div>
  158. <div class="table-card" v-if="state.tableParams.model === 'card'" :style="{
  159. gridTemplateColumns: `repeat(${tableConfigCpt.cardLayout}, 1fr)`
  160. }">
  161. <template v-for="(item, index) in state.tableParams.data">
  162. <div class="card-block">
  163. <div class="card-item __hover">
  164. <div class="main-row">
  165. <template v-if="tableConfigCpt?.cardImg.value">
  166. <div class="main-row-img">
  167. <el-image
  168. :src="item[tableConfigCpt?.cardImg.value]"
  169. :zoom-rate="1.2"
  170. :max-scale="7"
  171. :min-scale="0.2"
  172. :preview-src-list="[item[tableConfigCpt?.cardImg.value]]"
  173. :preview-teleported="true"
  174. />
  175. </div>
  176. </template>
  177. <div class="main-row-param">
  178. <CusEllipsis :value="item[tableConfigCpt.cardMain.value]" :html="true"/>
  179. </div>
  180. <!-- <div class="main-row-operation">-->
  181. <!-- <div class="__hover">-->
  182. <!-- <SvgIcon name="detail_1" color="var(&#45;&#45;cus-main-color)"/>详情-->
  183. <!-- </div>-->
  184. <!-- <div class="__hover">-->
  185. <!-- <SvgIcon name="archives_1" color="var(&#45;&#45;cus-main-color)"/>档案-->
  186. <!-- </div>-->
  187. <!-- </div>-->
  188. </div>
  189. <div class="cols" :style="{
  190. gridTemplateColumns: `repeat(${tableConfigCpt.cardCol}, 1fr)`
  191. }">
  192. <template v-for="c in tableConfigCpt.cardConfig">
  193. <div class="cols-item" :style="{
  194. gridColumn: `span ${c.col}`
  195. }">
  196. <div class="cols-item-label">{{c.key}}:</div>
  197. <div class="cols-item-value">
  198. <CusEllipsis :value="item[c.value]" :html="true"/>
  199. </div>
  200. </div>
  201. </template>
  202. </div>
  203. </div>
  204. </div>
  205. </template>
  206. </div>
  207. </div>
  208. <div class="table-content-page">
  209. <CusPage
  210. :page-num="state.tableParams.pageNum"
  211. :page-size="state.tableParams.pageSize"
  212. :total="state.tableParams.total"
  213. @page="onPage"
  214. />
  215. </div>
  216. </div>
  217. </div>
  218. </div>
  219. </div>
  220. </div>
  221. </template>
  222. <script setup lang="ts">
  223. import {computed, getCurrentInstance, onBeforeMount, onMounted, reactive, ref, watch} from "vue";
  224. import {useRoute, useRouter} from "vue-router";
  225. import {useAppStore, useWebStore} from "@/stores";
  226. import {ElLoading, ElMessage} from "element-plus";
  227. import {frontGetIndexAndFieldInfo} from "@/api/modules/web/list";
  228. const {proxy} = getCurrentInstance()
  229. const AppStore = useAppStore()
  230. const WebStore = useWebStore()
  231. const route = useRoute()
  232. const router = useRouter()
  233. const state: any = reactive({
  234. searchText: '',
  235. cascaderParams: {
  236. value: [],
  237. props: {
  238. label: 'treeName',
  239. value: 'treeId',
  240. multiple: true,
  241. emitPath: false
  242. },
  243. show: false,
  244. options: []
  245. },
  246. searchParams: {
  247. text: '',
  248. indexKey: []
  249. },
  250. resultParams: {
  251. tree: [],
  252. activeTab: '',
  253. activeIndex: '',
  254. indexConfig: {}
  255. },
  256. ws: {
  257. count: () => {},
  258. list: () => {},
  259. countPercent: 100
  260. },
  261. tableParams: {
  262. model: 'list',
  263. pageNum: 1,
  264. pageSize: 10,
  265. total: 0,
  266. data: [],
  267. loading: false
  268. }
  269. })
  270. const ref_area = ref()
  271. const isSelectAllCpt = computed(() => {
  272. return WebStore.searchAreaIndexTotal === state.cascaderParams.value.length
  273. })
  274. const currentIndexCpt = computed(() => {
  275. let obj = {}
  276. state.resultParams.tree.forEach(v => {
  277. v.children.forEach(c => {
  278. c.children.forEach(s => {
  279. if (s.treeId === state.resultParams.activeIndex) {
  280. obj = s
  281. }
  282. })
  283. })
  284. })
  285. return JSON.parse(JSON.stringify(obj))
  286. })
  287. const tableConfigCpt = computed(() => {
  288. const listConfig = []
  289. const cardConfig = []
  290. let cardMain = {}
  291. let cardImg = {}
  292. state.resultParams.indexConfig?.sysIndexFields?.forEach(v => {
  293. if (v.searchShow == 1) {
  294. const obj = {key: v.fieldNameCn, value: v.fieldNameEn, col: v.labelLength}
  295. listConfig.push(obj)
  296. if (v.pictureField == 1) {
  297. cardImg = obj
  298. } else {
  299. cardConfig.push(obj)
  300. }
  301. }
  302. })
  303. cardMain = cardConfig.shift()
  304. const res = {
  305. listCol: state.resultParams.indexConfig.columnModelNum,
  306. listConfig: listConfig,
  307. hasCard: true,
  308. cardLayout: state.resultParams.indexConfig.pictureModeCardNum,
  309. cardCol: state.resultParams.indexConfig.cardColumnNum,
  310. cardMain: cardMain,
  311. cardImg: cardImg,
  312. cardConfig: cardConfig
  313. }
  314. console.log(res)
  315. return res
  316. })
  317. const initArea = () => {
  318. WebStore.getSearchAreaTree().then(res => {
  319. const arr = []
  320. JSON.parse(JSON.stringify(res)).forEach(v => {
  321. v.children.forEach(c => {
  322. c.__children = JSON.parse(JSON.stringify(c.children))
  323. c.children = []
  324. })
  325. arr.push(v)
  326. })
  327. state.cascaderParams.options = arr
  328. onSearch()
  329. })
  330. }
  331. const onDelFilter = (index) => {
  332. const temp = JSON.parse(JSON.stringify(state.cascaderParams.value))
  333. temp.splice(index, 1)
  334. state.cascaderParams.value = temp
  335. }
  336. const onSearch = () => {
  337. if (state.searchText) {
  338. state.searchParams = JSON.parse(JSON.stringify({
  339. text: state.searchText,
  340. indexKey: state.cascaderParams.value
  341. }))
  342. initResultTree()
  343. } else {
  344. ElMessage({
  345. message: '请输入关键字进行查询!',
  346. grouping: true,
  347. type: 'warning',
  348. })
  349. }
  350. }
  351. const initResultTree = () => {
  352. state.resultParams.activeTab = ''
  353. state.resultParams.activeIndex = ''
  354. const arr = []
  355. WebStore.searchAreaTree.forEach(v => {
  356. const t = {
  357. ...v,
  358. children: []
  359. }
  360. v.children?.forEach(c => {
  361. if (state.searchParams.indexKey.includes(c.treeId)) {
  362. t.children.push(c)
  363. }
  364. })
  365. if (t.children.length > 0) {
  366. arr.push(t)
  367. }
  368. })
  369. if (arr.length > 0) {
  370. state.resultParams.tree = JSON.parse(JSON.stringify(arr))
  371. } else {
  372. state.resultParams.tree = JSON.parse(JSON.stringify(WebStore.searchAreaTree))
  373. }
  374. state.ws.count()
  375. }
  376. const getIndexConfig = () => {
  377. state.resultParams.indexConfig = {}
  378. proxy.$api.frontGetIndexAndFieldInfo(`id=${WebStore.searchAreaIndexMap.get(state.resultParams.activeIndex).id}`).then(res => {
  379. state.resultParams.indexConfig = res.data
  380. state.ws.list()
  381. })
  382. }
  383. const onPage = (pageNum, pageSize) => {
  384. state.tableParams.pageNum = pageNum
  385. state.tableParams.pageSize = pageSize
  386. state.ws.list(false)
  387. }
  388. watch(() => state.resultParams.activeIndex, (n) => {
  389. if (n) {
  390. getIndexConfig()
  391. }
  392. })
  393. onMounted(() => {
  394. const {text, index} = route.query
  395. if (!text) {
  396. router.replace({
  397. name: '71305311-abcc-4d13-8531-f966b49839c5'
  398. })
  399. } else {
  400. state.searchText = text
  401. if (index) {
  402. state.cascaderParams.value = index.split(',').map(v => Number(v))
  403. }
  404. let loading = null
  405. const ws: any = new WebSocket('/ws-api/smart-ws?userId=1388061846031220738')
  406. ws.onerror = () => {
  407. loading = ElLoading.service({
  408. lock: true,
  409. text: '智搜服务连接失败……',
  410. background: 'rgba(0, 0, 0, 0.7)',
  411. })
  412. }
  413. let sessionId = ''
  414. let lastCountParams = ''
  415. let lastCountStep = 0
  416. let lastCountStep_ = 0
  417. let lastListParams = ''
  418. ws.onopen = (e) => {
  419. state.ws.count = () => {
  420. state.ws.countPercent = 0
  421. // 如果有的话,终止上一次请求
  422. if (lastCountParams) {
  423. const p = JSON.parse(lastCountParams)
  424. p.flag = 'stop'
  425. ws.send(JSON.stringify(p))
  426. }
  427. // 如果有的话,终止上一次请求
  428. if (lastListParams) {
  429. const p = JSON.parse(lastListParams)
  430. p.flag = 'stop'
  431. ws.send(JSON.stringify(p))
  432. lastListParams = ''
  433. }
  434. // 执行新的请求
  435. let step = 0
  436. const builder = state.resultParams.tree.map(tag => ({
  437. tagCode: tag.treeId,
  438. datas: tag.children.map(type => {
  439. step++
  440. return {
  441. typeCode: type.treeId,
  442. datas: type.children.map(index => ({
  443. indexCode: index.treeId,
  444. }))
  445. }
  446. })
  447. }))
  448. lastCountStep = step
  449. lastCountStep_ = step
  450. const params = {
  451. builder: builder,
  452. keyData: state.searchParams.text,
  453. type: 'count',
  454. sessionId: sessionId,
  455. timestamp: new Date().getTime(),
  456. flag: 'run',
  457. orderBy: {}
  458. }
  459. lastCountParams = JSON.stringify(params)
  460. ws.send(lastCountParams)
  461. }
  462. state.ws.list = (init = true) => {
  463. // 如果有的话,终止上一次请求
  464. if (lastListParams) {
  465. const p = JSON.parse(lastListParams)
  466. p.flag = 'stop'
  467. ws.send(JSON.stringify(p))
  468. lastListParams = ''
  469. }
  470. if (init) {
  471. state.tableParams = {
  472. model: 'card',
  473. pageNum: 1,
  474. pageSize: 10,
  475. total: 0,
  476. data: [],
  477. loading: true
  478. }
  479. }
  480. const params = {
  481. keyData: state.searchParams.text,
  482. pageNumber: state.tableParams.pageNum,
  483. pageSize: state.tableParams.pageSize,
  484. indexCode: state.resultParams.activeIndex,
  485. type: 'list',
  486. sessionId: sessionId,
  487. timestamp: new Date().getTime(),
  488. flag: 'run',
  489. orderBy: {}
  490. }
  491. lastListParams = JSON.stringify(params)
  492. ws.send(lastListParams)
  493. }
  494. }
  495. ws.onmessage = (e) => {
  496. try {
  497. const json = JSON.parse(e.data)
  498. if (json.type === 'session') {
  499. sessionId = json.sessionId
  500. initArea()
  501. } else {
  502. switch (json.type) {
  503. case 'count': {
  504. const p = JSON.parse(lastCountParams)
  505. // 返回为最新批次的
  506. if (json.timestamp == p.timestamp) {
  507. const resTag = json.datas
  508. const resType = resTag.datas[0]
  509. state.resultParams.tree.forEach(tag => {
  510. if (tag.treeId == resTag.tagCode) {
  511. tag.children.forEach(type => {
  512. if (type.treeId == resType.typeCode) {
  513. resType.datas.forEach((index, indexI) => {
  514. type.children[indexI].__count = index.data
  515. type.__count = type.__count ? (type.__count + index.data) : index.data
  516. tag.__count = tag.__count ? (tag.__count + index.data) : index.data
  517. })
  518. }
  519. })
  520. }
  521. })
  522. for (let tagI = 0; tagI < state.resultParams.tree.length; tagI++) {
  523. const tag = state.resultParams.tree[tagI]
  524. if (tag.__count > 0 && !state.resultParams.activeTab) {
  525. state.resultParams.activeTab = tag.treeId
  526. for (let typeI = 0; typeI < tag.children.length; typeI++) {
  527. const type = tag.children[typeI]
  528. if (type.__count > 0) {
  529. type.__expend = true
  530. for (let indexI = 0; indexI < type.children.length; indexI++) {
  531. const index = type.children[indexI]
  532. if (index.__count > 0 && !state.resultParams.activeIndex) {
  533. state.resultParams.activeIndex = index.treeId
  534. break
  535. }
  536. }
  537. break
  538. }
  539. }
  540. break
  541. }
  542. }
  543. lastCountStep--
  544. state.ws.countPercent = ((lastCountStep_ - lastCountStep) / lastCountStep_ * 100).toFixed(0)
  545. if (lastCountStep === 0) {
  546. lastCountParams = ''
  547. }
  548. }
  549. } break
  550. case 'list': {
  551. const p = JSON.parse(lastListParams)
  552. // 返回为最新批次的
  553. if (json.timestamp == p.timestamp) {
  554. state.tableParams.total = json.records
  555. state.tableParams.data = json.datas
  556. state.tableParams.loading = false
  557. lastListParams = ''
  558. }
  559. } break
  560. }
  561. }
  562. } catch (e) {
  563. }
  564. }
  565. state.ws = ws
  566. }
  567. })
  568. </script>
  569. <style lang="scss" scoped>
  570. .list {
  571. width: 100%;
  572. height: 100%;
  573. background-color: #F6F7FB;
  574. display: flex;
  575. flex-direction: column;
  576. .list-head {
  577. .list-head-search {
  578. width: 800px;
  579. display: flex;
  580. align-items: center;
  581. height: 48px;
  582. background: rgba(255,255,255,0.9);
  583. box-shadow: 0px 0px 2px 0px rgba(167,220,255,0.5);
  584. border-radius: 60px;
  585. border: 1px solid var(--cus-text-color-4);
  586. .left-select {
  587. display: flex;
  588. align-items: center;
  589. justify-content: center;
  590. width: 184px;
  591. gap: 17px;
  592. color: var(--cus-text-color-4);
  593. font-size: 18px;
  594. position: relative;
  595. &:after {
  596. content: '';
  597. position: absolute;
  598. right: 0;
  599. height: 40px;
  600. width: 1px;
  601. background-color: var(--cus-text-color-4);
  602. }
  603. :deep(.area-cascader) {
  604. position: absolute;
  605. z-index: -1;
  606. opacity: 0;
  607. height: 50px;
  608. }
  609. }
  610. :deep(.el-input) {
  611. font-size: 18px;
  612. color: var(--cus-text-color-2);
  613. .el-input__wrapper {
  614. box-shadow: none !important;
  615. background-color: transparent;
  616. .el-input__inner {
  617. &::placeholder {
  618. color: var(--cus-text-color-4);
  619. }
  620. }
  621. }
  622. }
  623. .right-icon {
  624. margin-right: 20px;
  625. }
  626. }
  627. }
  628. .count-percent {
  629. display: flex;
  630. align-items: center;
  631. font-weight: 400;
  632. font-size: 10px;
  633. color: var(---cus-text-color-2);
  634. padding: 10px 24px;
  635. line-height: 1;
  636. .bar-bg {
  637. flex: 1;
  638. margin-right: 10px;
  639. background-color: rgba(var(--cus-main-color-rgb), 0.1);
  640. height: 8px;
  641. border-radius: 8px;
  642. position: relative;
  643. .bar-block {
  644. transition: 1s;
  645. border-radius: 8px;
  646. position: absolute;
  647. height: 100%;
  648. background-color: rgba(var(--cus-main-color-rgb), 1);
  649. }
  650. }
  651. }
  652. .list-content {
  653. overflow: hidden;
  654. flex: 1;
  655. padding: 0 24px 24px 24px;
  656. display: flex;
  657. flex-direction: column;
  658. $filterLineHeight: 26px;
  659. .list-filter {
  660. font-weight: 500;
  661. font-size: 14px;
  662. color: var(--cus-text-color-2);
  663. display: flex;
  664. .label {
  665. margin-right: 20px;
  666. line-height: $filterLineHeight;
  667. }
  668. .value {
  669. flex: 1;
  670. display: flex;
  671. flex-wrap: wrap;
  672. gap: 10px 10px;
  673. .filter-item {
  674. height: $filterLineHeight;
  675. padding: 0 16px;
  676. background: #FFFFFF;
  677. border-radius: 45px;
  678. font-size: 12px;
  679. display: flex;
  680. align-items: center;
  681. .svg-icon {
  682. margin-left: 10px;
  683. }
  684. }
  685. }
  686. }
  687. .list-tab {
  688. height: 45px;
  689. margin-top: 19px;
  690. display: flex;
  691. .list-tab-item {
  692. height: 100%;
  693. padding: 0 16px;
  694. display: flex;
  695. align-items: center;
  696. justify-content: center;
  697. color: var(--cus-text-color-2);
  698. border-radius: 8px 8px 0 0;
  699. .total {
  700. font-size: 12px;
  701. margin-left: 4px;
  702. color: var(--cus-text-color-2);
  703. font-weight: 400;
  704. }
  705. &.active {
  706. background-color: #ffffff;
  707. box-shadow: 0px -4px 10px 0px rgba(62,123,250,0.1);
  708. color: var(--cus-main-color);
  709. font-weight: 500;
  710. position: relative;
  711. &:after {
  712. content: '';
  713. position: absolute;
  714. bottom: 0;
  715. width: calc(100% - 16px * 2);
  716. height: 3px;
  717. background-color: var(--cus-main-color);
  718. }
  719. }
  720. }
  721. }
  722. .list-result {
  723. flex: 1;
  724. background-color: #ffffff;
  725. padding: 16px;
  726. display: flex;
  727. gap: 16px;
  728. overflow: hidden;
  729. .list-result-tree {
  730. height: 100%;
  731. width: 300px;
  732. padding-right: 10px;
  733. overflow-y: auto;
  734. .list-result-tree-item {
  735. .item-parent {
  736. min-height: 38px;
  737. display: flex;
  738. align-items: center;
  739. padding-right: 16px;
  740. line-height: 1;
  741. color: var(--cus-text-color-1);
  742. .flag {
  743. margin-right: 10px;
  744. }
  745. .total {
  746. font-size: 14px;
  747. }
  748. .expend {
  749. margin-left: auto;
  750. }
  751. }
  752. .item-son {
  753. padding: 10px 34px;
  754. font-weight: 400;
  755. font-size: 14px;
  756. color: var(--cus-text-color-2);
  757. border-radius: 4px;
  758. .total {
  759. font-size: 12px;
  760. }
  761. &.active {
  762. background-color: rgba(var(--cus-main-color-rgb), 0.1);
  763. color: var(--cus-main-color);
  764. }
  765. }
  766. }
  767. }
  768. .list-result-table {
  769. display: flex;
  770. flex-direction: column;
  771. flex: 1;
  772. overflow: hidden;
  773. .table-head {
  774. width: 100%;
  775. height: 162px;
  776. padding: 16px;
  777. background: linear-gradient( 90deg, rgba(var(--cus-main-color-rgb),0.1) 0%, rgba(var(--cus-main-color-rgb),0.05) 100%), #FFFFFF;
  778. box-shadow: 0px 2px 4px 0px rgba(var(--cus-main-color-rgb),0.3);
  779. border-radius: 4px;
  780. display: flex;
  781. flex-direction: column;
  782. .table-head-index {
  783. display: flex;
  784. align-items: center;
  785. padding-right: 16px;
  786. line-height: 1;
  787. color: var(--cus-text-color-1);
  788. .flag {
  789. margin-right: 10px;
  790. }
  791. .total {
  792. font-size: 14px;
  793. }
  794. }
  795. .table-head-infos {
  796. flex: 1;
  797. display: flex;
  798. align-items: flex-end;
  799. overflow: hidden;
  800. gap: 10px;
  801. .main {
  802. height: 92px;
  803. min-width: 455px;
  804. display: flex;
  805. align-items: center;
  806. background: linear-gradient( 90deg, rgba(var(--cus-main-color-rgb),0.2) 0%, rgba(var(--cus-main-color-rgb),0.15) 100%);
  807. font-weight: 400;
  808. font-size: 12px;
  809. position: relative;
  810. &:before {
  811. content: '';
  812. background-image: url("@/assets/images/web/wen-list_table-head-bg-2.png");
  813. background-repeat: no-repeat;
  814. background-size: 100% 100%;
  815. position: absolute;
  816. width: 100%;
  817. height: 100%;
  818. z-index: 1;
  819. }
  820. >* {
  821. z-index: 2;
  822. }
  823. >img {
  824. margin-left: 24px;
  825. height: 100%;
  826. }
  827. >div {
  828. >div {
  829. &:nth-child(odd) {
  830. color: var(--cus-text-color-3);
  831. }
  832. &:nth-child(even) {
  833. color: var(--cus-text-color-2);
  834. }
  835. &:nth-child(2) {
  836. margin-bottom: 6px;
  837. }
  838. }
  839. }
  840. .one {
  841. margin: 0 32px;
  842. }
  843. }
  844. .info {
  845. height: 100%;
  846. flex: 1;
  847. overflow: hidden;
  848. display: flex;
  849. align-items: flex-end;
  850. .block {
  851. width: 100%;
  852. height: 70px;
  853. background: linear-gradient( 90deg, rgba(var(--cus-main-color-rgb),0.2) 0%, rgba(var(--cus-main-color-rgb),0.15) 100%);
  854. position: relative;
  855. display: grid;
  856. &:before {
  857. content: '';
  858. background-image: url("@/assets/images/web/wen-list_table-head-bg-1.png");
  859. background-repeat: no-repeat;
  860. background-size: 100% 100%;
  861. position: absolute;
  862. width: 100%;
  863. height: 100%;
  864. z-index: 1;
  865. }
  866. >* {
  867. z-index: 2;
  868. }
  869. >img {
  870. position: absolute;
  871. bottom: 0;
  872. left: 20px;
  873. }
  874. .text {
  875. margin-left: 144px;
  876. margin-top: 14px;
  877. position: inherit;
  878. width: calc(100% - 144px);
  879. overflow: hidden;
  880. .text-title {
  881. width: 100%;
  882. font-weight: 400;
  883. font-size: 14px;
  884. color: var(--cus-text-color-2);
  885. }
  886. .text-value {
  887. width: 100%;
  888. margin-top: 4px;
  889. font-weight: 500;
  890. font-size: 16px;
  891. color: var(--cus-main-color);
  892. >span {
  893. font-size: 12px;
  894. }
  895. }
  896. }
  897. }
  898. }
  899. }
  900. }
  901. .table-switch {
  902. margin: 10px 0 10px auto;
  903. display: flex;
  904. >div {
  905. width: 34px;
  906. height: 34px;
  907. display: flex;
  908. align-items: center;
  909. justify-content: center;
  910. background-color: #F5F7FA;
  911. border: 1px solid #DCDFE5;
  912. &:nth-child(1) {
  913. border-radius: 4px 0 0 4px;
  914. }
  915. &:nth-child(2) {
  916. border-radius: 0 4px 4px 0;
  917. }
  918. &.active {
  919. background-color: var(--cus-main-color);
  920. border-color: var(--cus-main-color);
  921. }
  922. }
  923. }
  924. .table-content {
  925. flex: 1;
  926. display: flex;
  927. flex-direction: column;
  928. overflow: hidden;
  929. .table-content-result {
  930. flex: 1;
  931. overflow: hidden;
  932. .table-list {
  933. width: 100%;
  934. height: 100%;
  935. display: flex;
  936. flex-direction: column;
  937. overflow-y: auto;
  938. border: 1px solid #EAEBEF;
  939. border-radius: 4px;
  940. .list-item {
  941. display: flex;
  942. align-items: center;
  943. font-weight: 400;
  944. font-size: 14px;
  945. color: var(--cus-text-color-2);
  946. padding: 12px 16px;
  947. &:hover {
  948. background-color: rgba(46,129,255,0.05);
  949. }
  950. &:not(:last-child) {
  951. border-bottom: 1px solid #EAEBEF;
  952. }
  953. .index {
  954. margin-right: 16px;
  955. }
  956. .cols {
  957. flex: 1;
  958. display: grid;
  959. row-gap: 4px;
  960. .cols-item {
  961. display: flex;
  962. overflow: hidden;
  963. .cols-item-label {
  964. color: var(--cus-text-color-1);
  965. font-weight: bold;
  966. }
  967. .cols-item-value {
  968. flex: 1;
  969. overflow: hidden;
  970. color: var(--cus-text-color-2);
  971. }
  972. }
  973. }
  974. .operation {
  975. display: flex;
  976. align-items: center;
  977. gap: 10px;
  978. font-size: 14px;
  979. color: var(--cus-text-color-2);
  980. >div {
  981. display: flex;
  982. align-items: center;
  983. .svg-icon {
  984. margin-right: 2px;
  985. }
  986. }
  987. }
  988. }
  989. }
  990. .table-card {
  991. width: 100%;
  992. height: 100%;
  993. display: grid;
  994. overflow-y: auto;
  995. gap: 16px;
  996. padding-bottom: 4px;
  997. padding-right: 4px;
  998. .card-block {
  999. overflow: hidden;
  1000. height: max-content;
  1001. box-shadow: 0px 2px 4px 0px rgba(var(--cus-main-color-rgb),0.2);
  1002. .card-item {
  1003. padding: 16px;
  1004. background: linear-gradient( 180deg, rgba(var(--cus-main-color-rgb), 0.1) 0%, rgba(var(--cus-main-color-rgb),0) 100%), #FFFFFF;
  1005. border-radius: 4px;
  1006. .main-row {
  1007. display: flex;
  1008. align-items: center;
  1009. .main-row-img {
  1010. width: 40px;
  1011. height: 40px;
  1012. border-radius: 4px;
  1013. margin-right: 10px;
  1014. .el-image {
  1015. width: 100%;
  1016. height: 100%;
  1017. >img {
  1018. width: 100%;
  1019. height: 100%;
  1020. }
  1021. }
  1022. }
  1023. .main-row-param {
  1024. flex: 1;
  1025. font-size: 20px;
  1026. color: var(--cus-text-color-1);
  1027. font-weight: bold;
  1028. overflow: hidden;
  1029. }
  1030. .main-row-operation {
  1031. display: flex;
  1032. align-items: center;
  1033. gap: 10px;
  1034. font-size: 14px;
  1035. color: var(--cus-text-color-2);
  1036. margin-left: auto;
  1037. >div {
  1038. display: flex;
  1039. align-items: center;
  1040. .svg-icon {
  1041. margin-right: 2px;
  1042. }
  1043. }
  1044. }
  1045. }
  1046. .cols {
  1047. display: grid;
  1048. row-gap: 4px;
  1049. font-size: 14px;
  1050. .cols-item {
  1051. display: flex;
  1052. overflow: hidden;
  1053. .cols-item-label {
  1054. color: var(--cus-text-color-1);
  1055. font-weight: bold;
  1056. }
  1057. .cols-item-value {
  1058. flex: 1;
  1059. overflow: hidden;
  1060. color: var(--cus-text-color-2);
  1061. }
  1062. }
  1063. }
  1064. }
  1065. }
  1066. }
  1067. }
  1068. .table-content-page {
  1069. margin-top: 10px;
  1070. margin-left: auto;
  1071. }
  1072. }
  1073. }
  1074. }
  1075. }
  1076. }
  1077. .list-move, /* 对移动中的元素应用的过渡 */
  1078. .list-enter-active,
  1079. .list-leave-active {
  1080. transition: all 0.1s ease;
  1081. }
  1082. .list-enter-from,
  1083. .list-leave-to {
  1084. opacity: 0;
  1085. }
  1086. .list-leave-active {
  1087. }
  1088. </style>