<template>

  <div class="app-container dict-page">

    <div class="dict-page-header">

      <div class="dict-page-title">字典管理</div>

      <div class="dict-page-desc">维护平台/租户字典，导入平台模板后统一下发至各租户</div>

    </div>



    <el-steps :active="stepActive" finish-status="success" align-center class="dict-steps mb16" simple>

      <el-step title="字典维护" icon="el-icon-edit-outline" />

      <el-step title="平台模板" icon="el-icon-document-copy" />

      <el-step title="同步下发" icon="el-icon-upload2" />

    </el-steps>



    <el-tabs v-model="activeTab" @tab-click="onTabChange" class="dict-main-tabs">

      <!-- ========== Tab1：字典维护 ========== -->

      <el-tab-pane label="字典维护" name="dict">

        <div class="dict-tab-panel">

          <div class="mode-banner" :class="tenantId ? 'is-tenant' : 'is-platform'">

            <i :class="tenantId ? 'el-icon-office-building' : 'el-icon-s-platform'" />

            <div class="mode-banner-text">

              <strong>{{ tenantId ? '租户字典模式' : '平台主库模式' }}</strong>

              <span>{{ tenantId ? '当前租户：' + (tenantName || tenantId) : '未选择租户时，维护平台主库字典（原有字典管理）' }}</span>

            </div>

          </div>



          <el-card shadow="never" class="mb16 filter-card" v-show="showSearch">

            <el-form :model="queryParams" ref="queryForm" :inline="true" size="small" label-width="72px">

              <el-form-item label="租户">

                <inline-tenant-selector ref="tenantSelector" mode="admin" @change="onTenantChange" />

              </el-form-item>

              <el-form-item label="字典名称" prop="dictName">

                <el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable @keyup.enter.native="handleQuery" />

              </el-form-item>

              <el-form-item label="字典类型" prop="dictType">

                <el-input v-model="queryParams.dictType" placeholder="请输入字典类型" clearable @keyup.enter.native="handleQuery" />

              </el-form-item>

              <el-form-item label="状态" prop="status">

                <el-select v-model="queryParams.status" placeholder="字典状态" clearable style="width: 120px">

                  <el-option v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />

                </el-select>

              </el-form-item>

              <el-form-item v-if="!isTenantMode" label="创建时间">

                <el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始" end-placeholder="结束" />

              </el-form-item>

              <el-form-item>

                <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>

                <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>

              </el-form-item>

            </el-form>

          </el-card>



          <el-row :gutter="10" class="mb8 toolbar-row">

            <el-col :span="1.5">

              <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="addPermi">新增</el-button>

            </el-col>

            <el-col :span="1.5">

              <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="editPermi">修改</el-button>

            </el-col>

            <el-col :span="1.5">

              <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="removePermi">删除</el-button>

            </el-col>

            <el-col :span="1.5" v-if="!isTenantMode">

              <el-button type="warning" plain icon="el-icon-download" size="mini" :loading="exportLoading" @click="handleExport" v-hasPermi="['system:dict:export']">导出</el-button>

            </el-col>

            <el-col :span="1.5">

              <el-button type="primary" plain icon="el-icon-upload2" size="mini" :disabled="multiple" @click="handleImportToTemplate" v-hasPermi="['tenant:dict:template:add']">导入到平台模板</el-button>

            </el-col>

            <el-col :span="1.5">

              <el-button type="info" plain icon="el-icon-refresh" size="mini" @click="handleRefreshCache" v-hasPermi="editPermi">刷新缓存</el-button>

            </el-col>

            <el-col :span="1.5" v-if="isTenantMode">

              <el-button type="warning" plain icon="el-icon-right" size="mini" @click="activeTab = 'sync'" v-hasPermi="['tenant:dict:sync']">去同步下发</el-button>

            </el-col>

            <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />

          </el-row>



          <el-table v-loading="loading" :data="typeList" border size="small" @selection-change="handleSelectionChange" class="dict-table">

            <el-table-column type="selection" width="48" align="center" />

            <el-table-column label="字典编号" align="center" prop="dictId" width="88" />

            <el-table-column label="字典名称" align="center" prop="dictName" min-width="120" :show-overflow-tooltip="true" />

            <el-table-column label="字典类型" align="center" min-width="140" :show-overflow-tooltip="true">

              <template slot-scope="scope">

                <router-link :to="dictDataRoute(scope.row.dictId)" class="link-type">

                  <span>{{ scope.row.dictType }}</span>

                </router-link>

              </template>

            </el-table-column>

            <el-table-column v-if="isTenantMode" label="来源" align="center" width="76">

              <template slot-scope="scope">

                <el-tag size="mini" :type="scope.row.dictSource === 'platform' ? 'warning' : 'success'">

                  {{ scope.row.dictSource === 'platform' ? '平台' : '租户' }}

                </el-tag>

              </template>

            </el-table-column>

            <el-table-column v-if="isTenantMode" label="平台管控" align="center" width="88">

              <template slot-scope="scope">

                <el-tag size="mini" :type="scope.row.isPlatformManaged === 1 ? 'danger' : 'info'">

                  {{ scope.row.isPlatformManaged === 1 ? '是' : '否' }}

                </el-tag>

              </template>

            </el-table-column>

            <el-table-column label="状态" align="center" prop="status" width="76">

              <template slot-scope="scope">

                <dict-tag :options="statusOptions" :value="scope.row.status"/>

              </template>

            </el-table-column>

            <el-table-column label="备注" align="center" prop="remark" min-width="100" :show-overflow-tooltip="true" />

            <el-table-column label="创建时间" align="center" prop="createTime" width="158">

              <template slot-scope="scope">

                <span>{{ parseTime(scope.row.createTime) }}</span>

              </template>

            </el-table-column>

            <el-table-column label="操作" align="center" width="130" fixed="right" class-name="small-padding fixed-width">

              <template slot-scope="scope">

                <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="editPermi">修改</el-button>

                <el-button size="mini" type="text" icon="el-icon-delete" style="color:#f5222d" @click="handleDelete(scope.row)" v-hasPermi="removePermi">删除</el-button>

              </template>

            </el-table-column>

          </el-table>



          <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />

        </div>



        <el-dialog :title="title" :visible.sync="open" width="520px" append-to-body>

          <el-form ref="form" :model="form" :rules="rules" label-width="80px">

            <el-form-item label="字典名称" prop="dictName"><el-input v-model="form.dictName" /></el-form-item>

            <el-form-item label="字典类型" prop="dictType"><el-input v-model="form.dictType" :disabled="form.dictId != null" /></el-form-item>

            <el-form-item label="状态" prop="status">

              <el-radio-group v-model="form.status">

                <el-radio v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictValue">{{ dict.dictLabel }}</el-radio>

              </el-radio-group>

            </el-form-item>

            <el-form-item label="备注"><el-input v-model="form.remark" type="textarea" /></el-form-item>

          </el-form>

          <div slot="footer" class="dialog-footer">

            <el-button type="primary" @click="submitForm">确 定</el-button>

            <el-button @click="cancel">取 消</el-button>

          </div>

        </el-dialog>

      </el-tab-pane>



      <el-tab-pane label="平台模板" name="template" lazy>

        <tenant-dict-template />

      </el-tab-pane>



      <el-tab-pane label="同步下发" name="sync" lazy>

        <tenant-dict-sync />

      </el-tab-pane>

    </el-tabs>

  </div>

</template>



<script>

import InlineTenantSelector from '@/components/InlineTenantSelector'

import TenantDictTemplate from '@/views/admin/tenantDict/template/index'

import TenantDictSync from '@/views/admin/tenantDict/sync/index'

import { listType, getType, delType, addType, updateType, exportType, refreshCache } from '@/api/system/dict/type'

import {

  listTenantDictType, getTenantDictType, addTenantDictType,

  updateTenantDictType, delTenantDictType, refreshTenantDictCache,

  importTemplateFromPlatform, importTemplateFromTenant

} from '@/api/tenant/dict'



export default {

  name: 'Dict',

  components: { InlineTenantSelector, TenantDictTemplate, TenantDictSync },

  data() {

    return {

      activeTab: 'dict',

      tenantId: null,

      tenantName: '',

      loading: true,

      exportLoading: false,

      ids: [],

      selectedRows: [],

      single: true,

      multiple: true,

      showSearch: true,

      total: 0,

      typeList: [],

      title: '',

      open: false,

      statusOptions: [],

      dateRange: [],

      queryParams: { pageNum: 1, pageSize: 10, dictName: undefined, dictType: undefined, status: undefined },

      form: {},

      rules: {

        dictName: [{ required: true, message: '字典名称不能为空', trigger: 'blur' }],

        dictType: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }]

      }

    }

  },

  computed: {

    isTenantMode() { return !!this.tenantId },

    isAdminRoute() { return this.$route.path.indexOf('/admin') === 0 },

    addPermi() { return this.isTenantMode ? ['tenant:dict:add'] : ['system:dict:add'] },

    editPermi() { return this.isTenantMode ? ['tenant:dict:edit'] : ['system:dict:edit'] },

    removePermi() { return this.isTenantMode ? ['tenant:dict:remove'] : ['system:dict:remove'] },

    stepActive() {

      const map = { dict: 0, template: 1, sync: 2 }

      return map[this.activeTab] != null ? map[this.activeTab] : 0

    }

  },

  created() {

    if (this.$route.query.tab) this.activeTab = this.$route.query.tab

    this.initTenantContext()

    this.getDicts('sys_normal_disable').then(r => { this.statusOptions = r.data })

    this.getList()

  },

  mounted() {

    this.syncTenantSelector()

  },

  watch: {

    '$route.query.tenantId'(val) {

      this.initTenantContext(val ? Number(val) : null)

      this.syncTenantSelector()

      this.getList()

    }

  },

  methods: {

    onTabChange() {},

    initTenantContext(routeTenantId) {

      const fromQuery = routeTenantId !== undefined

        ? routeTenantId

        : (this.$route.query.tenantId ? Number(this.$route.query.tenantId) : null)

      this.tenantId = fromQuery || null

      if (this.tenantId) {

        this.$store.dispatch('tenant/setCompanyId', this.tenantId)

      }

    },

    syncTenantSelector() {

      if (!this.$refs.tenantSelector) return

      const sel = this.$refs.tenantSelector

      if (this.tenantId) {

        sel.selectedId = this.tenantId

        const item = (sel.tenantList || []).find(t => t.id === this.tenantId)

        this.tenantName = item && item.tenantName ? item.tenantName : this.tenantName

        if (!item && sel.tenantList && !sel.tenantList.length) {

          const unwatch = this.$watch(() => sel.tenantList.length, len => {

            if (!len) return

            const loaded = sel.tenantList.find(t => t.id === this.tenantId)

            if (loaded) this.tenantName = loaded.tenantName

            unwatch()

          })

        }

      } else {

        sel.selectedId = null

        this.tenantName = ''

      }

    },

    syncTenantRouteQuery() {

      const query = { ...this.$route.query }

      if (this.tenantId) query.tenantId = this.tenantId

      else delete query.tenantId

      if (String(query.tenantId || '') === String(this.$route.query.tenantId || '')) return

      this.$router.replace({ path: this.$route.path, query })

    },

    onTenantChange(val, item) {

      this.tenantId = val || null

      this.tenantName = item && item.tenantName ? item.tenantName : ''

      this.queryParams.pageNum = 1

      if (val) {

        this.$store.dispatch('tenant/setCompanyId', val)

      }

      this.syncTenantRouteQuery()

      this.getList()

    },

    isPlatformLocked(row) {
      if (!row) return false
      return Number(row.isPlatformManaged) === 1
    },
    assertNotPlatformLocked(rows) {
      if (!this.isTenantMode) return true
      const locked = (rows || []).filter(r => this.isPlatformLocked(r))
      if (!locked.length) return true
      this.$message.warning('「' + locked[0].dictName + '」为平台管控字典，请通过「平台模板 + 同步下发」维护')
      return false
    },

    dictDataRoute(dictId) {

      const base = this.isAdminRoute ? '/admin/dict-data/index/' : '/system/dict-data/index/'

      const query = { from: this.$route.fullPath }

      if (this.isTenantMode) query.tenantId = this.tenantId

      return { path: base + dictId, query }

    },

    getList() {

      this.loading = true

      const params = this.isTenantMode ? this.queryParams : this.addDateRange(this.queryParams, this.dateRange)

      const req = this.isTenantMode

        ? listTenantDictType(this.tenantId, params)

        : listType(params)

      req.then(response => {

        this.typeList = response.rows

        this.total = response.total

        this.loading = false

      }).catch(() => { this.loading = false })

    },

    cancel() { this.open = false; this.reset() },

    reset() {

      this.form = { dictId: undefined, dictName: undefined, dictType: undefined, status: '0', remark: undefined }

      this.resetForm('form')

    },

    handleQuery() { this.queryParams.pageNum = 1; this.getList() },

    resetQuery() {

      this.dateRange = []

      this.resetForm('queryForm')

      if (this.$refs.tenantSelector) {

        this.$refs.tenantSelector.reset()

      }

      this.tenantId = null

      this.tenantName = ''

      this.syncTenantRouteQuery()

      this.handleQuery()

    },

    handleAdd() { this.reset(); this.open = true; this.title = '添加字典类型' },

    handleSelectionChange(selection) {

      this.selectedRows = selection

      this.ids = selection.map(item => item.dictId)

      this.single = selection.length !== 1

      this.multiple = !selection.length

    },

    handleImportToTemplate() {

      if (!this.selectedRows.length) {

        this.$message.warning('请先勾选要导入的字典类型')

        return

      }

      this.$confirm('将选中字典的类型及全部字典数据导入到「平台模板」，已存在项默认仅追加缺失数据。是否继续？', '导入确认', { type: 'info' })

        .then(() => {

          const req = this.isTenantMode

            ? importTemplateFromTenant({

              tenantId: this.tenantId,

              dictTypes: this.selectedRows.map(r => r.dictType),

              overwriteExisting: false

            })

            : importTemplateFromPlatform({

              dictIds: this.selectedRows.map(r => r.dictId),

              overwriteExisting: false

            })

          return req.then(r => {

            this.$message.success(r.data.message || '已导入到平台模板')

            this.activeTab = 'template'

          })

        }).catch(() => {})

    },

    handleUpdate(row) {
      const target = row && row.dictId ? row : this.selectedRows[0]
      if (this.isTenantMode && target && !this.assertNotPlatformLocked([target])) return
      this.reset()
      const dictId = (target && target.dictId) || this.ids[0]
      const req = this.isTenantMode ? getTenantDictType(this.tenantId, dictId) : getType(dictId)
      req.then(response => { this.form = response.data; this.open = true; this.title = '修改字典类型' })
    },

    submitForm() {

      this.$refs['form'].validate(valid => {

        if (!valid) return

        let req

        if (this.isTenantMode) {

          const payload = { ...this.form }

          delete payload.dictSource

          delete payload.isPlatformManaged

          req = this.form.dictId != null

            ? updateTenantDictType(this.tenantId, payload)

            : addTenantDictType(this.tenantId, payload)

        } else {

          req = this.form.dictId != null ? updateType(this.form) : addType(this.form)

        }

        req.then(() => {
          this.msgSuccess(this.form.dictId != null ? '修改成功' : '新增成功')
          this.open = false
          this.getList()
        }).catch(err => {
          this.$message.error((err && err.message) || err || '保存失败')
        })

      })

    },

    handleDelete(row) {
      const targets = row && row.dictId ? [row] : this.selectedRows
      if (this.isTenantMode && !this.assertNotPlatformLocked(targets)) return
      const dictIds = row.dictId || this.ids.join(',')
      this.$confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?', '警告', { type: 'warning' })
        .then(() => this.isTenantMode ? delTenantDictType(this.tenantId, dictIds) : delType(dictIds))
        .then(() => { this.getList(); this.msgSuccess('删除成功') })
        .catch(err => {
          if (err && err !== 'cancel') {
            this.$message.error((err && err.message) || err || '删除失败')
          }
        })
    },

    handleExport() {

      this.$confirm('是否确认导出所有类型数据项?', '警告', { type: 'warning' }).then(() => {

        this.exportLoading = true

        return exportType(this.queryParams)

      }).then(response => {

        this.download(response.msg)

        this.exportLoading = false

      }).catch(() => { this.exportLoading = false })

    },

    handleRefreshCache() {

      const req = this.isTenantMode ? refreshTenantDictCache(this.tenantId) : refreshCache()

      req.then(() => this.msgSuccess('刷新成功'))

    }

  }

}

</script>



<style scoped>

.dict-page-header { margin-bottom: 12px; }

.dict-page-title { font-size: 18px; font-weight: 600; color: #303133; line-height: 1.4; }

.dict-page-desc { margin-top: 4px; font-size: 13px; color: #909399; }

.dict-steps { background: #f5f7fa; border-radius: 8px; padding: 12px 16px; }

.dict-main-tabs >>> .el-tabs__header { margin-bottom: 16px; }

.dict-main-tabs >>> .el-tabs__item { font-size: 14px; height: 42px; line-height: 42px; }

.dict-tab-panel { padding-top: 4px; }

.mode-banner {

  display: flex;

  align-items: center;

  gap: 12px;

  padding: 12px 16px;

  border-radius: 8px;

  margin-bottom: 16px;

  border: 1px solid transparent;

}

.mode-banner i { font-size: 22px; }

.mode-banner-text { display: flex; flex-direction: column; gap: 2px; font-size: 13px; color: #606266; }

.mode-banner-text strong { font-size: 14px; color: #303133; }

.mode-banner.is-platform { background: #ecf5ff; border-color: #d9ecff; color: #409eff; }

.mode-banner.is-platform i { color: #409eff; }

.mode-banner.is-tenant { background: #f0f9eb; border-color: #e1f3d8; color: #67c23a; }

.mode-banner.is-tenant i { color: #67c23a; }

.mb8 { margin-bottom: 8px; }

.mb16 { margin-bottom: 16px; }

.filter-card { padding-bottom: 0; }

.toolbar-row { display: flex; flex-wrap: wrap; align-items: center; }

.dict-table { width: 100%; }

</style>


