| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- <template>
- <div
- v-loading="loading"
- class="l-flex--col u-color--black u-font-size--sm u-relative"
- :class="{ shrink: shrinkState }"
- >
- <el-tabs
- v-if="exact"
- v-model="active"
- class="c-tabs has-bottom-padding"
- >
- <el-tab-pane
- label="按部门"
- name="group"
- />
- <el-tab-pane
- label="按分辨率"
- name="ratio"
- />
- <el-tab-pane
- label="按宽高比"
- name="productType"
- />
- </el-tabs>
- <warning
- v-if="error"
- @click="getDevices"
- />
- <template v-else>
- <div class="l-flex__none l-flex--row c-sibling-item--v u-overflow--hidden">
- <div class="l-flex__auto" />
- <search-input
- v-model.trim="deviceName"
- class="l-flex__none"
- placeholder="设备名称"
- @search="onSearch"
- />
- </div>
- <c-tree
- class="l-flex__fill c-sibling-item--v"
- :root-option="rootOption"
- />
- </template>
- <i
- v-if="shrink"
- class="o-shrink-icon u-color--black u-font-size--lg has-active"
- :class="iconClass"
- @click="onToggleShrink"
- />
- </div>
- </template>
- <script>
- import {
- getDepartmentDeviceTree,
- getProduct
- } from '@/api/device'
- import treeMixin from '../tree.js'
- export default {
- name: 'DeviceTree',
- mixins: [treeMixin],
- props: {
- shrink: {
- type: [Boolean, String],
- default: false
- },
- exact: {
- type: [Boolean, String],
- default: false
- },
- filter: {
- type: Function,
- default: null
- }
- },
- data () {
- return {
- shrinkState: false,
- loading: false,
- error: false,
- active: 'group',
- deviceName: ''
- }
- },
- computed: {
- isGroupTab () {
- return this.active === 'group'
- },
- iconClass () {
- return this.shrinkState ? 'el-icon-d-arrow-right' : 'el-icon-d-arrow-left'
- }
- },
- watch: {
- active: {
- handler () {
- this.getDevices()
- },
- immediate: true
- }
- },
- methods: {
- onToggleShrink () {
- this.shrinkState = !this.shrinkState
- },
- getDevices () {
- this.loading = true
- this.error = false
- this.getDevicesByActive().then(
- data => {
- this.$nodes = data
- this.onSearch()
- },
- () => {
- this.error = true
- }
- ).finally(() => {
- this.loading = false
- })
- },
- getDevicesByActive () {
- if (this.$productCache) {
- return this.initTabCache()
- }
- const cache = this[`$${this.active}Cache`]
- if (cache) {
- return Promise.resolve(cache)
- }
- return getDepartmentDeviceTree().then(({ data }) => {
- const productCacheOptions = {
- key: 'productId',
- ids: {},
- map: {},
- cache: []
- }
- this.$groupCache = this.iterateNode(data, productCacheOptions).children
- if (this.exact) {
- this.$productCache = productCacheOptions.cache
- }
- return this.getDevicesByActive()
- })
- },
- async initTabCache () {
- for (let i = 0; i < this.$productCache.length; i++) {
- if (!this.$productCache[i].resolutionRatio) {
- const { data: { resolutionRatio, productTypeName } } = await getProduct(this.$productCache[i].id)
- this.$productCache[i].resolutionRatio = resolutionRatio
- this.$productCache[i].productTypeName = productTypeName
- this.$productCache[i].children.forEach(device => {
- device.resolutionRatio = resolutionRatio
- })
- }
- }
- const ratioMap = {}
- const productTypeMap = {}
- this.$productCache.forEach(({ resolutionRatio, productTypeName, children }) => {
- if (!ratioMap[resolutionRatio]) {
- ratioMap[resolutionRatio] = []
- }
- ratioMap[resolutionRatio] = [...ratioMap[resolutionRatio], ...children]
- if (!productTypeMap[productTypeName]) {
- productTypeMap[productTypeName] = []
- }
- productTypeMap[productTypeName] = [...productTypeMap[productTypeName], ...children]
- })
- this.$ratioCache = Object.keys(ratioMap).map(key => {
- return {
- id: key,
- name: key,
- children: ratioMap[key]
- }
- })
- this.$productTypeCache = Object.keys(productTypeMap).map(key => {
- return {
- id: key,
- name: key,
- children: productTypeMap[key]
- }
- })
- this.$productCache = null
- return this.getDevicesByActive()
- },
- iterateNode ({ id = 'root', name = '我的部门', children, devices }, productCacheOptions) {
- const deviceArr = []
- devices.forEach(device => {
- const item = this.transform(device)
- this.setCache(item, productCacheOptions)
- deviceArr.push(item)
- })
- return {
- id: `dir_${id}`,
- name,
- children: [
- ...children.map(child => this.iterateNode(child, productCacheOptions)),
- ...deviceArr
- ]
- }
- },
- transform ({ id, name, productId }) {
- return {
- id, name, productId
- }
- },
- setCache (device, { key, ids, map, cache }) {
- const id = device.id
- if (!ids[id]) {
- const value = device[key]
- if (!map[value]) {
- map[value] = []
- cache.push({
- id: value,
- children: map[value]
- })
- }
- ids[id] = 1
- map[value].push(device)
- }
- },
- onSearch () {
- const regx = this.deviceName ? new RegExp(this.deviceName) : null
- const rootOption = this.createNode()
- this.setNodes(rootOption, this.onFilter(rootOption, this.$nodes, regx))
- this.rootOption = rootOption
- this.customExpand = !!this.deviceName
- },
- onFilter (parent, nodes, regx) {
- if (regx) {
- nodes = nodes.filter(({ children, name }) => {
- if (children) {
- return true
- }
- return regx.test(name)
- })
- }
- const childNodes = nodes.map(({ children, ...node }) => {
- if (!children) {
- const leafNode = this.createLeafNode(parent, node)
- if (this.filter) {
- leafNode.disabled = !this.filter(node)
- }
- return leafNode
- }
- const subNode = this.createNode(node, parent)
- this.setNodes(subNode, this.onFilter(subNode, children, regx))
- return subNode
- })
- if (this.hideDisabled) {
- return childNodes.filter(({ disabled }) => !disabled)
- }
- return childNodes
- },
- reset () {
- this.onSearch()
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .shrink {
- box-sizing: border-box;
- width: $spacing !important;
- }
- .o-shrink-icon {
- position: absolute;
- top: 50%;
- right: 0;
- transform: translateY(-50%);
- }
- </style>
|