|
|
@@ -0,0 +1,1738 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+ <!-- 页面头部 -->
|
|
|
+ <div class="page-header">
|
|
|
+ <el-icon class="back-icon" @click="goBack"><ArrowLeft /></el-icon>
|
|
|
+ <span class="page-title">查看授权</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 设置授权 -->
|
|
|
+ <div class="form-section">
|
|
|
+ <div class="section-title">设置授权</div>
|
|
|
+
|
|
|
+ <el-form :model="formData" label-width="100px" class="auth-form">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="品牌名称:">
|
|
|
+ <el-select
|
|
|
+ v-if="!isEditMode"
|
|
|
+ v-model="formData.brandName"
|
|
|
+ placeholder="请选择"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ style="width: 100%;"
|
|
|
+ @change="handleBrandChange"
|
|
|
+ @clear="handleBrandClear"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="brand in brandList"
|
|
|
+ :key="brand.id"
|
|
|
+ :label="brand.brandName"
|
|
|
+ :value="brand.brandName"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ v-model="formData.brandName"
|
|
|
+ readonly
|
|
|
+ style="width: 100%;"
|
|
|
+ placeholder="品牌名称"
|
|
|
+ class="readonly-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="商标注册人:">
|
|
|
+ <el-input v-model="formData.brandRegistrant" readonly style="width: 100%;" placeholder="商标注册人" class="readonly-input readonly-not-allowed" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="授权类型:">
|
|
|
+ <el-select
|
|
|
+ v-model="formData.authorizeTypeId"
|
|
|
+ placeholder="请选择"
|
|
|
+ clearable
|
|
|
+ style="width: 100%;"
|
|
|
+ @change="handleAuthorizeTypeChange"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in authorizeTypeList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.authorizeType"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 第一行:三个分类下拉框 -->
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-form-item label="选择分类:">
|
|
|
+ <el-select
|
|
|
+ v-if="!isEditMode"
|
|
|
+ v-model="formData.category1"
|
|
|
+ placeholder="请选择"
|
|
|
+ clearable
|
|
|
+ style="width: 100%;"
|
|
|
+ @change="handleCategory1Change"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in category1List"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.categoryName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ :value="categoryDisplayNames.oneLevelName"
|
|
|
+ readonly
|
|
|
+ style="width: 100%;"
|
|
|
+ placeholder="一级分类"
|
|
|
+ class="readonly-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-form-item label=" ">
|
|
|
+ <el-select
|
|
|
+ v-if="!isEditMode"
|
|
|
+ v-model="formData.category2"
|
|
|
+ placeholder="请选择"
|
|
|
+ clearable
|
|
|
+ style="width: 100%;"
|
|
|
+ :disabled="!formData.category1"
|
|
|
+ @change="handleCategory2Change"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in category2List"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.categoryName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ :value="categoryDisplayNames.twoLevelName"
|
|
|
+ readonly
|
|
|
+ style="width: 100%;"
|
|
|
+ placeholder="二级分类"
|
|
|
+ class="readonly-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-form-item label=" ">
|
|
|
+ <el-select
|
|
|
+ v-if="!isEditMode"
|
|
|
+ v-model="formData.category3"
|
|
|
+ placeholder="请选择"
|
|
|
+ clearable
|
|
|
+ style="width: 100%;"
|
|
|
+ :disabled="!formData.category2"
|
|
|
+ @change="handleCategory3Change"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in category3List"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.categoryName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ :value="categoryDisplayNames.threeLevelName"
|
|
|
+ readonly
|
|
|
+ style="width: 100%;"
|
|
|
+ placeholder="三级分类"
|
|
|
+ class="readonly-input"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-button v-if="!isEditMode" type="primary" icon="Plus" @click="handleAddCategory">添加分类</el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 额外添加的分类行(只有二级和三级) -->
|
|
|
+ <div v-for="row in extraCategoryRows" :key="row.id" class="extra-category-row">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-form-item label=" ">
|
|
|
+ <!-- 占位,保持对齐 -->
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-form-item label=" ">
|
|
|
+ <el-select
|
|
|
+ v-model="row.category2"
|
|
|
+ placeholder="请选择"
|
|
|
+ clearable
|
|
|
+ style="width: 100%;"
|
|
|
+ @change="(val) => handleExtraCategory2Change(row, val)"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in row.category2List"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.categoryName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-form-item label=" ">
|
|
|
+ <el-select
|
|
|
+ v-model="row.category3"
|
|
|
+ placeholder="请选择"
|
|
|
+ clearable
|
|
|
+ style="width: 100%;"
|
|
|
+ :disabled="!row.category2"
|
|
|
+ @change="(val) => handleExtraCategory3Change(row, val)"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in row.category3List"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.categoryName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-button type="danger" icon="Delete" @click="handleDeleteCategory(row)">删除分类</el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 授权链路 -->
|
|
|
+ <el-form-item label="授权链路:">
|
|
|
+ <div class="auth-chain-container">
|
|
|
+ <!-- 授权链路自定义表格 -->
|
|
|
+ <div class="auth-chain-custom-table">
|
|
|
+ <div class="auth-chain-header">
|
|
|
+ <div
|
|
|
+ v-for="level in authChainLevels"
|
|
|
+ :key="'h-' + level.id"
|
|
|
+ class="auth-chain-cell header-cell"
|
|
|
+ >
|
|
|
+ {{ level.label }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="auth-chain-row">
|
|
|
+ <div
|
|
|
+ v-for="level in authChainLevels"
|
|
|
+ :key="'c-' + level.id"
|
|
|
+ class="auth-chain-cell"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-if="level.editable"
|
|
|
+ v-model="level.value"
|
|
|
+ :placeholder="level.placeholder"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ <span v-else>{{ level.value }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 原来的授权人员输入(保留或删除,根据需求) -->
|
|
|
+ <!-- <el-form-item>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.authPerson"
|
|
|
+ placeholder="请输入品牌授权人"
|
|
|
+ style="width: 300px;"
|
|
|
+ />
|
|
|
+ <el-button type="primary" icon="Plus" style="margin-left: 10px;" @click="handleAddPerson">
|
|
|
+ 添加品牌授权人
|
|
|
+ </el-button>
|
|
|
+ <el-button icon="Delete" @click="handleDeletePerson">删除</el-button>
|
|
|
+ </el-form-item> -->
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <!-- 资质文件 -->
|
|
|
+ <div class="file-section">
|
|
|
+ <div class="file-title">资质文件</div>
|
|
|
+ <el-table :data="fileList" border style="width: 100%">
|
|
|
+ <el-table-column prop="index" label="序号" align="center" width="80" />
|
|
|
+ <el-table-column prop="typeName" label="资质名称" align="center" width="150" />
|
|
|
+ <el-table-column label="文件名称" align="center" min-width="400">
|
|
|
+ <template #default="scope">
|
|
|
+ <div v-if="scope.row.fileOssIds" class="file-name-list">
|
|
|
+ <div v-for="(fileName, idx) in getFileNames(scope.row.fileOssIds)" :key="idx" class="file-name-item">
|
|
|
+ {{ fileName }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <span v-else style="color: #999;">暂无文件</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="资质文件" align="center" width="250">
|
|
|
+ <template #default="scope">
|
|
|
+ <div class="file-actions">
|
|
|
+ <template v-if="scope.row.fileOssIds">
|
|
|
+ <el-button type="primary" link @click="handleDownloadFile(scope.row)">下载</el-button>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="资质到期日" align="center" width="220">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="scope.row.expireDate"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择到期日"
|
|
|
+ style="width: 100%;"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 文件上传对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="fileUploadDialogVisible"
|
|
|
+ title="上传资质文件"
|
|
|
+ width="600px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <FileUpload
|
|
|
+ v-model="currentFileRow.fileOssIds"
|
|
|
+ :limit="5"
|
|
|
+ :file-size="10"
|
|
|
+ :file-type="['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx']"
|
|
|
+ />
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="fileUploadDialogVisible = false">关闭</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 授权区域 -->
|
|
|
+ <div class="area-section">
|
|
|
+ <div class="area-title">
|
|
|
+ <span>授权区域:</span>
|
|
|
+ </div>
|
|
|
+ <el-table :data="areaList" border style="width: 100%">
|
|
|
+ <el-table-column type="index" label="序号" align="center" width="80" />
|
|
|
+ <el-table-column prop="province" label="授权区域(省)" align="center" />
|
|
|
+ <el-table-column prop="city" label="授权区域(市)" align="center" />
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 提交按钮 -->
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 授权区域选择对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="areaDialogVisible"
|
|
|
+ title="选择授权区域"
|
|
|
+ width="700px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <el-cascader
|
|
|
+ v-model="selectedAreas"
|
|
|
+ :options="areaOptions"
|
|
|
+ :props="cascaderProps"
|
|
|
+ placeholder="请选择授权区域"
|
|
|
+ style="width: 100%;"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ />
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="areaDialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" :loading="areaSubmitLoading" @click="handleAreaSubmit">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, onMounted, watch } from 'vue';
|
|
|
+import { useRouter, useRoute } from 'vue-router';
|
|
|
+import { ArrowLeft } from '@element-plus/icons-vue';
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
+import { listBrand } from '@/api/product/brand';
|
|
|
+import { listCategory } from '@/api/product/category';
|
|
|
+import type { CategoryVO } from '@/api/product/category/types';
|
|
|
+import { listByIds } from '@/api/system/oss';
|
|
|
+import { addSupplierauthorize, getBrandAuthorizeDetail, updateSupplierauthorize } from '@/api/supplier/supplierauthorize';
|
|
|
+import type { SupplierauthorizeForm } from '@/api/supplier/supplierauthorize/types';
|
|
|
+import type { QualificationFileForm } from '@/api/supplier/qualificationFile/types';
|
|
|
+import { listAuthorizetypeLevel } from '@/api/supplier/authorizetypeLevel';
|
|
|
+import type { AuthorizetypeLevelVO } from '@/api/supplier/authorizetypeLevel/types';
|
|
|
+import { useUserStore } from '@/store/modules/user';
|
|
|
+import FileUpload from '@/components/FileUpload/index.vue';
|
|
|
+import { regionData } from 'element-china-area-data';
|
|
|
+
|
|
|
+const router = useRouter();
|
|
|
+const route = useRoute();
|
|
|
+const userStore = useUserStore();
|
|
|
+
|
|
|
+// 判断是新增还是编辑模式
|
|
|
+const editId = ref<string | number>('');
|
|
|
+const isEditMode = ref(false);
|
|
|
+
|
|
|
+// 分类显示名称(编辑模式用)
|
|
|
+const categoryDisplayNames = ref({
|
|
|
+ oneLevelName: '',
|
|
|
+ twoLevelName: '',
|
|
|
+ threeLevelName: ''
|
|
|
+});
|
|
|
+
|
|
|
+// 表单数据
|
|
|
+const formData = ref({
|
|
|
+ brandId: '',
|
|
|
+ brandNo: '',
|
|
|
+ brandName: '',
|
|
|
+ brandLogo: '', // 品牌LOGO
|
|
|
+ brandRegistrant: '', // 商标注册人
|
|
|
+ authorizeTypeId: '', // 授权类型ID
|
|
|
+ authorizeLevel: '', // 授权等级
|
|
|
+ category1: '', // 第一行的一级分类
|
|
|
+ category2: '', // 第一行的二级分类
|
|
|
+ category3: '', // 第一行的三级分类
|
|
|
+ authPerson: ''
|
|
|
+});
|
|
|
+
|
|
|
+// 品牌列表
|
|
|
+const brandList = ref<any[]>([]);
|
|
|
+
|
|
|
+// 授权类型列表
|
|
|
+const authorizeTypeList = ref<AuthorizetypeLevelVO[]>([]);
|
|
|
+
|
|
|
+// 授权链路
|
|
|
+interface AuthChainLevel {
|
|
|
+ id: number; // 唯一标识
|
|
|
+ label: string; // 列标题(0级授权、1级授权...)
|
|
|
+ value: string; // 授权人名称
|
|
|
+ editable: boolean; // 是否可编辑
|
|
|
+ placeholder: string; // 输入框提示
|
|
|
+}
|
|
|
+
|
|
|
+let authLevelIdCounter = 0;
|
|
|
+
|
|
|
+const authChainLevels = ref<AuthChainLevel[]>([
|
|
|
+ {
|
|
|
+ id: authLevelIdCounter++,
|
|
|
+ label: '0级授权',
|
|
|
+ value: '',
|
|
|
+ editable: true,
|
|
|
+ placeholder: '请输入授权人'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: authLevelIdCounter++,
|
|
|
+ label: '1级授权',
|
|
|
+ value: '优易达(武汉)有限公司',
|
|
|
+ editable: false,
|
|
|
+ placeholder: ''
|
|
|
+ }
|
|
|
+]);
|
|
|
+
|
|
|
+const refreshAuthChainEditable = () => {
|
|
|
+ if (!authChainLevels.value?.length) return;
|
|
|
+ authChainLevels.value.forEach((lvl, idx) => (lvl.editable = idx !== authChainLevels.value.length - 1));
|
|
|
+};
|
|
|
+
|
|
|
+refreshAuthChainEditable();
|
|
|
+
|
|
|
+// 第一行的分类列表
|
|
|
+const category1List = ref<CategoryVO[]>([]); // 一级分类
|
|
|
+const category2List = ref<CategoryVO[]>([]); // 二级分类
|
|
|
+const category3List = ref<CategoryVO[]>([]); // 三级分类
|
|
|
+
|
|
|
+// 额外添加的分类行(只有二级和三级)
|
|
|
+interface ExtraCategoryRow {
|
|
|
+ id: number;
|
|
|
+ category2: string | number;
|
|
|
+ category3: string | number;
|
|
|
+ category2List: CategoryVO[];
|
|
|
+ category3List: CategoryVO[];
|
|
|
+}
|
|
|
+
|
|
|
+const extraCategoryRows = ref<ExtraCategoryRow[]>([]);
|
|
|
+let extraCategoryRowIdCounter = 0;
|
|
|
+
|
|
|
+// 资质文件列表
|
|
|
+const fileList = ref([
|
|
|
+ {
|
|
|
+ index: 1,
|
|
|
+ typeName: '商标注册证',
|
|
|
+ fileOssIds: '',
|
|
|
+ expireDate: '',
|
|
|
+ fileDetails: [] as any[] // 缓存文件详情
|
|
|
+ },
|
|
|
+ {
|
|
|
+ index: 2,
|
|
|
+ typeName: '品牌授权书',
|
|
|
+ fileOssIds: '',
|
|
|
+ expireDate: '',
|
|
|
+ fileDetails: [] as any[]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ index: 3,
|
|
|
+ typeName: '质检报告',
|
|
|
+ fileOssIds: '',
|
|
|
+ expireDate: '',
|
|
|
+ fileDetails: [] as any[]
|
|
|
+ }
|
|
|
+]);
|
|
|
+
|
|
|
+// 文件名称缓存
|
|
|
+const fileNamesCache = ref<Map<string, string[]>>(new Map());
|
|
|
+
|
|
|
+// 文件上传对话框
|
|
|
+const fileUploadDialogVisible = ref(false);
|
|
|
+const currentFileRow = ref<any>({});
|
|
|
+
|
|
|
+// 授权区域列表
|
|
|
+const areaList = ref<any[]>([]);
|
|
|
+
|
|
|
+// 授权区域对话框相关
|
|
|
+const areaDialogVisible = ref(false);
|
|
|
+const areaSubmitLoading = ref(false);
|
|
|
+const selectedAreas = ref<any[]>([]); // 选中的授权区域(级联选择器的值)
|
|
|
+const areaOptions = ref<any[]>([]); // 授权区域选项(从接口获取)
|
|
|
+const selectedAreaIds = ref<string[]>([]); // 选中的区域ID列表(用于提交)
|
|
|
+
|
|
|
+const cascaderProps = {
|
|
|
+ multiple: true,
|
|
|
+ value: 'value', // 使用 component 自带的 value(即行政区划代码如 110000)
|
|
|
+ label: 'label',
|
|
|
+ children: 'children',
|
|
|
+ checkStrictly: false,
|
|
|
+ emitPath: true
|
|
|
+};
|
|
|
+
|
|
|
+const toProvinceCityOptions = (options: any[]) => {
|
|
|
+ return (options || []).map((province) => {
|
|
|
+ const provinceValue6 = String(province.value ?? '');
|
|
|
+ const provinceValue = provinceValue6.length >= 2 ? provinceValue6.slice(0, 2) : provinceValue6;
|
|
|
+
|
|
|
+ const cities = (province.children || []).map((city: any) => {
|
|
|
+ const cityValue6 = String(city.value ?? '');
|
|
|
+ const cityValue = cityValue6.length >= 4 ? cityValue6.slice(0, 4) : cityValue6;
|
|
|
+ const { children, ...rest } = city;
|
|
|
+ return {
|
|
|
+ ...rest,
|
|
|
+ value: cityValue
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...province,
|
|
|
+ value: provinceValue,
|
|
|
+ children: cities
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const isCityCode = (val: any) => {
|
|
|
+ const s = String(val ?? '').trim();
|
|
|
+ return /^\d{4}$/.test(s);
|
|
|
+};
|
|
|
+
|
|
|
+/** 返回 */
|
|
|
+const goBack = () => {
|
|
|
+ router.back();
|
|
|
+};
|
|
|
+
|
|
|
+/** 加载详情数据(编辑模式) */
|
|
|
+const loadDetailData = async () => {
|
|
|
+ try {
|
|
|
+ console.log('=== 加载详情数据 ===');
|
|
|
+ console.log('编辑ID:', editId.value);
|
|
|
+
|
|
|
+ const res = await getBrandAuthorizeDetail(editId.value);
|
|
|
+ const data = res.data;
|
|
|
+
|
|
|
+ console.log('详情数据:', data);
|
|
|
+
|
|
|
+ // 回显基本信息
|
|
|
+ formData.value.brandNo = (data as any).brandNo || '';
|
|
|
+ formData.value.brandName = data.brandName || '';
|
|
|
+ formData.value.brandLogo = data.brandLogo || '';
|
|
|
+ formData.value.brandRegistrant = data.brandRegistrant || (data as any).registrationCertificate || '';
|
|
|
+ formData.value.authorizeTypeId = Number(data.authorizeType) || '';
|
|
|
+ formData.value.authorizeLevel = data.authorizeLevel || '';
|
|
|
+
|
|
|
+ // 根据品牌名称找到对应的品牌ID(需要等待品牌列表加载完成)
|
|
|
+ if (data.brandName) {
|
|
|
+ // 如果品牌列表还没加载完成,等待一下
|
|
|
+ let retryCount = 0;
|
|
|
+ while (brandList.value.length === 0 && retryCount < 10) {
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
+ retryCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (brandList.value.length > 0) {
|
|
|
+ const matchedBrand = brandList.value.find(brand => brand.brandName === data.brandName);
|
|
|
+ if (matchedBrand) {
|
|
|
+ formData.value.brandId = matchedBrand.id;
|
|
|
+ console.log('根据品牌名称找到品牌ID:', { brandName: data.brandName, brandId: matchedBrand.id });
|
|
|
+ } else {
|
|
|
+ // 如果找不到匹配的品牌,设置一个临时ID避免验证失败
|
|
|
+ formData.value.brandId = 'edit_mode_brand_id';
|
|
|
+ console.warn('未找到匹配的品牌,使用临时ID');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ formData.value.brandId = 'edit_mode_brand_id';
|
|
|
+ console.warn('品牌列表未加载,使用临时ID');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('授权类型回显:', {
|
|
|
+ 原始值: data.authorizeType,
|
|
|
+ 转换后: Number(data.authorizeType),
|
|
|
+ 类型: typeof Number(data.authorizeType)
|
|
|
+ });
|
|
|
+
|
|
|
+ // 回显分类信息(根据 categoryId 和 categorysMap)
|
|
|
+ if (data.categoryId && data.categorysMap) {
|
|
|
+ // 设置三级分类ID(这是实际需要提交的)
|
|
|
+ formData.value.category3 = data.categoryId;
|
|
|
+
|
|
|
+ // 为了通过验证,也设置一级和二级分类的临时值
|
|
|
+ formData.value.category1 = 'edit_mode_category1';
|
|
|
+ formData.value.category2 = 'edit_mode_category2';
|
|
|
+
|
|
|
+ // 存储分类名称用于显示
|
|
|
+ categoryDisplayNames.value = {
|
|
|
+ oneLevelName: data.categorysMap.oneLevelName || '',
|
|
|
+ twoLevelName: data.categorysMap.twoLevelName || '',
|
|
|
+ threeLevelName: data.categorysMap.threeLevelName || ''
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('分类信息回显:', {
|
|
|
+ categoryId: data.categoryId,
|
|
|
+ names: categoryDisplayNames.value,
|
|
|
+ formData: {
|
|
|
+ category1: formData.value.category1,
|
|
|
+ category2: formData.value.category2,
|
|
|
+ category3: formData.value.category3
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 回显授权链路
|
|
|
+ if (data.brandLicensor) {
|
|
|
+ const licensors = data.brandLicensor.split(',');
|
|
|
+ authChainLevels.value = [];
|
|
|
+
|
|
|
+ licensors.forEach((licensor, index) => {
|
|
|
+ authChainLevels.value.push({
|
|
|
+ id: authLevelIdCounter++,
|
|
|
+ label: `${index}级授权`,
|
|
|
+ value: licensor.trim(),
|
|
|
+ editable: index !== licensors.length - 1,
|
|
|
+ placeholder: '请输入授权人'
|
|
|
+ });
|
|
|
+ });
|
|
|
+ console.log('授权链路回显:', authChainLevels.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 回显授权区域
|
|
|
+ if (data.authorizedArea) {
|
|
|
+ const areaIds = data.authorizedArea.split(',');
|
|
|
+ selectedAreaIds.value = areaIds;
|
|
|
+
|
|
|
+ // 为级联选择器设置选中值
|
|
|
+ // 需要根据区域ID在 areaOptions 中找到对应的省市关系
|
|
|
+ selectedAreas.value = await buildCascaderValues(areaIds);
|
|
|
+
|
|
|
+ areaList.value = buildAreaRows(selectedAreas.value);
|
|
|
+ console.log('授权区域回显:', {
|
|
|
+ areaIds,
|
|
|
+ selectedAreas: selectedAreas.value,
|
|
|
+ rows: areaList.value
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 回显资质文件
|
|
|
+ if (data.qualificationFiles && data.qualificationFiles.length > 0) {
|
|
|
+ // 按文件类型分组
|
|
|
+ const filesByType = {
|
|
|
+ '商标注册证': [],
|
|
|
+ '品牌授权书': [],
|
|
|
+ '质检报告': []
|
|
|
+ };
|
|
|
+
|
|
|
+ data.qualificationFiles.forEach(file => {
|
|
|
+ if (filesByType[file.name]) {
|
|
|
+ filesByType[file.name].push(file);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 回显到对应的文件列表
|
|
|
+ fileList.value.forEach(fileRow => {
|
|
|
+ const files = filesByType[fileRow.typeName];
|
|
|
+ if (files && files.length > 0) {
|
|
|
+ // 构造 OSS ID 字符串(模拟上传组件的格式)
|
|
|
+ const ossIds = files.map(f => f.id).join(',');
|
|
|
+ fileRow.fileOssIds = ossIds;
|
|
|
+
|
|
|
+ // 缓存文件详情
|
|
|
+ fileRow.fileDetails = files.map(f => ({
|
|
|
+ id: f.id,
|
|
|
+ originalName: f.fileName,
|
|
|
+ url: f.fileUrl,
|
|
|
+ fileSuffix: f.fileType
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 设置到期日期(使用第一个文件的到期日期)
|
|
|
+ if (files[0].endTime) {
|
|
|
+ fileRow.expireDate = files[0].endTime.split(' ')[0]; // 只取日期部分
|
|
|
+ }
|
|
|
+
|
|
|
+ // 缓存文件名称
|
|
|
+ const fileNames = files.map(f => f.fileName);
|
|
|
+ fileNamesCache.value.set(ossIds, fileNames);
|
|
|
+
|
|
|
+ console.log(`${fileRow.typeName} 文件回显:`, {
|
|
|
+ ossIds,
|
|
|
+ fileNames,
|
|
|
+ fileDetails: fileRow.fileDetails,
|
|
|
+ expireDate: fileRow.expireDate
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('资质文件回显完成:', fileList.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ ElMessage.success('数据加载成功');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载详情数据失败:', error);
|
|
|
+ ElMessage.error('加载数据失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const handleBrandClear = () => {
|
|
|
+ formData.value.brandId = '';
|
|
|
+ formData.value.brandNo = '';
|
|
|
+ formData.value.brandName = '';
|
|
|
+ formData.value.brandLogo = '';
|
|
|
+ formData.value.brandRegistrant = '';
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/** 根据三级分类ID加载分类信息 */
|
|
|
+const loadCategoryByThirdLevel = async (categoryId: string | number) => {
|
|
|
+ // 这里需要根据三级分类ID反向查找一级、二级分类
|
|
|
+ // 暂时留空,后续需要完善
|
|
|
+ console.log('需要根据三级分类ID加载分类信息:', categoryId);
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取品牌列表 */
|
|
|
+const getBrandList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listBrand({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+ brandList.value = res.rows || [];
|
|
|
+ console.log('品牌列表:', brandList.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取品牌列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取授权类型列表 */
|
|
|
+const getAuthorizeTypeList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listAuthorizetypeLevel({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 100
|
|
|
+ });
|
|
|
+ authorizeTypeList.value = res.rows || [];
|
|
|
+ console.log('授权类型列表:', authorizeTypeList.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取授权类型列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 授权类型改变 */
|
|
|
+const handleAuthorizeTypeChange = (id: string | number) => {
|
|
|
+ const selected = authorizeTypeList.value.find(item => item.id === id);
|
|
|
+ if (selected) {
|
|
|
+ formData.value.authorizeLevel = String(selected.authorizeLevel);
|
|
|
+ console.log('选择授权类型:', {
|
|
|
+ id: id,
|
|
|
+ authorizeType: selected.authorizeType,
|
|
|
+ authorizeLevel: selected.authorizeLevel
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 品牌选择改变 */
|
|
|
+const handleBrandChange = (brandName: string) => {
|
|
|
+ if (!brandName) {
|
|
|
+ formData.value.brandId = '';
|
|
|
+ formData.value.brandNo = '';
|
|
|
+ formData.value.brandName = '';
|
|
|
+ formData.value.brandLogo = '';
|
|
|
+ formData.value.brandRegistrant = '';
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const selectedBrand = brandList.value.find(b => b.brandName === brandName);
|
|
|
+ if (selectedBrand) {
|
|
|
+ formData.value.brandId = selectedBrand.id;
|
|
|
+ formData.value.brandNo = selectedBrand.brandNo || '';
|
|
|
+ formData.value.brandName = selectedBrand.brandName;
|
|
|
+ formData.value.brandLogo = selectedBrand.brandLogo || ''; // 保存品牌LOGO
|
|
|
+ formData.value.brandRegistrant = selectedBrand.registrationCertificate || selectedBrand.brandRegistrant || '';
|
|
|
+ console.log('选择品牌:', {
|
|
|
+ brandId: formData.value.brandId,
|
|
|
+ brandNo: formData.value.brandNo,
|
|
|
+ brandName: formData.value.brandName,
|
|
|
+ brandLogo: formData.value.brandLogo,
|
|
|
+ brandRegistrant: formData.value.brandRegistrant
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取一级分类列表 */
|
|
|
+const getCategory1List = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listCategory({
|
|
|
+ classLevel: 1,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+ category1List.value = res.rows || [];
|
|
|
+ console.log('一级分类:', category1List.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取一级分类失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 第一行:一级分类改变 */
|
|
|
+const handleCategory1Change = async (value: string | number) => {
|
|
|
+ // 清空二级和三级分类
|
|
|
+ formData.value.category2 = '';
|
|
|
+ formData.value.category3 = '';
|
|
|
+ category2List.value = [];
|
|
|
+ category3List.value = [];
|
|
|
+
|
|
|
+ // 清空所有额外的分类行
|
|
|
+ extraCategoryRows.value = [];
|
|
|
+
|
|
|
+ if (!value) return;
|
|
|
+
|
|
|
+ // 根据一级分类ID查询二级分类
|
|
|
+ try {
|
|
|
+ const res = await listCategory({
|
|
|
+ parentId: value,
|
|
|
+ classLevel: 2,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+ category2List.value = res.rows || [];
|
|
|
+ console.log('二级分类:', category2List.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取二级分类失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取所有已选中的三级分类ID */
|
|
|
+const getSelectedCategory3Ids = (): (string | number)[] => {
|
|
|
+ const ids: (string | number)[] = [];
|
|
|
+
|
|
|
+ // 第一行的三级分类
|
|
|
+ if (formData.value.category3) {
|
|
|
+ ids.push(formData.value.category3);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 额外行的三级分类
|
|
|
+ extraCategoryRows.value.forEach(row => {
|
|
|
+ if (row.category3) {
|
|
|
+ ids.push(row.category3);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return ids;
|
|
|
+};
|
|
|
+
|
|
|
+/** 第一行:二级分类改变 */
|
|
|
+const handleCategory2Change = async (value: string | number) => {
|
|
|
+ // 清空三级分类
|
|
|
+ formData.value.category3 = '';
|
|
|
+ category3List.value = [];
|
|
|
+
|
|
|
+ if (!value) return;
|
|
|
+
|
|
|
+ // 根据二级分类ID查询三级分类
|
|
|
+ try {
|
|
|
+ const res = await listCategory({
|
|
|
+ parentId: value,
|
|
|
+ classLevel: 3,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+
|
|
|
+ // 过滤掉已选中的三级分类(排除当前行自己的选择)
|
|
|
+ const selectedIds = extraCategoryRows.value
|
|
|
+ .map(row => row.category3)
|
|
|
+ .filter(id => id);
|
|
|
+
|
|
|
+ category3List.value = (res.rows || []).filter(
|
|
|
+ (item: CategoryVO) => !selectedIds.includes(item.id)
|
|
|
+ );
|
|
|
+
|
|
|
+ console.log('三级分类:', category3List.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取三级分类失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 第一行:三级分类改变 */
|
|
|
+const handleCategory3Change = (value: string | number) => {
|
|
|
+ if (!value) return;
|
|
|
+
|
|
|
+ // 检查是否已经在额外行中选择了相同的三级分类
|
|
|
+ const isDuplicate = extraCategoryRows.value.some(row => row.category3 === value);
|
|
|
+
|
|
|
+ if (isDuplicate) {
|
|
|
+ ElMessage.warning('该分类已经选择过了,请选择其他分类');
|
|
|
+ formData.value.category3 = '';
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 额外行:二级分类改变 */
|
|
|
+const handleExtraCategory2Change = async (row: ExtraCategoryRow, value: string | number) => {
|
|
|
+ // 清空三级分类
|
|
|
+ row.category3 = '';
|
|
|
+ row.category3List = [];
|
|
|
+
|
|
|
+ if (!value) return;
|
|
|
+
|
|
|
+ // 根据二级分类ID查询三级分类
|
|
|
+ try {
|
|
|
+ const res = await listCategory({
|
|
|
+ parentId: value,
|
|
|
+ classLevel: 3,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+
|
|
|
+ // 过滤掉已选中的三级分类(排除当前行自己的选择)
|
|
|
+ const selectedIds = getSelectedCategory3Ids().filter(id => id !== row.category3);
|
|
|
+
|
|
|
+ row.category3List = (res.rows || []).filter(
|
|
|
+ (item: CategoryVO) => !selectedIds.includes(item.id)
|
|
|
+ );
|
|
|
+
|
|
|
+ console.log('额外行三级分类:', row.category3List);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取三级分类失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 额外行:三级分类改变 */
|
|
|
+const handleExtraCategory3Change = (row: ExtraCategoryRow, value: string | number) => {
|
|
|
+ if (!value) return;
|
|
|
+
|
|
|
+ // 检查是否与第一行的三级分类重复
|
|
|
+ if (formData.value.category3 === value) {
|
|
|
+ ElMessage.warning('该分类已经选择过了,请选择其他分类');
|
|
|
+ row.category3 = '';
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否与其他额外行的三级分类重复
|
|
|
+ const isDuplicate = extraCategoryRows.value.some(r => r.id !== row.id && r.category3 === value);
|
|
|
+
|
|
|
+ if (isDuplicate) {
|
|
|
+ ElMessage.warning('该分类已经选择过了,请选择其他分类');
|
|
|
+ row.category3 = '';
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 添加分类行(只添加二级和三级) */
|
|
|
+const handleAddCategory = async () => {
|
|
|
+ // 必须先选择一级分类
|
|
|
+ if (!formData.value.category1) {
|
|
|
+ ElMessage.warning('请先选择一级分类');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用第一行的二级分类列表
|
|
|
+ extraCategoryRows.value.push({
|
|
|
+ id: ++extraCategoryRowIdCounter,
|
|
|
+ category2: '',
|
|
|
+ category3: '',
|
|
|
+ category2List: [...category2List.value], // 复用第一行的二级分类列表
|
|
|
+ category3List: []
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('添加额外分类行,当前行数:', extraCategoryRows.value.length);
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除额外分类行 */
|
|
|
+const handleDeleteCategory = (row: ExtraCategoryRow) => {
|
|
|
+ const index = extraCategoryRows.value.findIndex(r => r.id === row.id);
|
|
|
+ if (index > -1) {
|
|
|
+ extraCategoryRows.value.splice(index, 1);
|
|
|
+ ElMessage.success('删除成功');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 添加授权人 */
|
|
|
+const handleAddPerson = () => {
|
|
|
+ if (!formData.value.authPerson) {
|
|
|
+ ElMessage.warning('请输入授权人');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ElMessage.success('授权人添加成功');
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除授权人 */
|
|
|
+const handleDeletePerson = () => {
|
|
|
+ formData.value.authPerson = '';
|
|
|
+ ElMessage.success('删除成功');
|
|
|
+};
|
|
|
+
|
|
|
+/** 添加授权级别 */
|
|
|
+const handleAddAuthLevel = () => {
|
|
|
+ if (authChainLevels.value.length >= 5) {
|
|
|
+ ElMessage.warning('授权链路最多支持5个级别');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 在最前面插入新的0级授权
|
|
|
+ // 所有现有级别的标签都要+1
|
|
|
+ const newLevels: AuthChainLevel[] = [
|
|
|
+ {
|
|
|
+ id: authLevelIdCounter++,
|
|
|
+ label: '0级授权',
|
|
|
+ value: '',
|
|
|
+ editable: true,
|
|
|
+ placeholder: '请输入授权人'
|
|
|
+ }
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 将现有的级别标签都+1
|
|
|
+ authChainLevels.value.forEach((level, index) => {
|
|
|
+ newLevels.push({
|
|
|
+ id: level.id, // 保持唯一身份标识避免页面组件渲染错误
|
|
|
+ label: `${index + 1}级授权`,
|
|
|
+ value: level.value,
|
|
|
+ editable: true,
|
|
|
+ placeholder: level.placeholder
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 仅最后一级不可编辑
|
|
|
+ if (newLevels.length) {
|
|
|
+ newLevels.forEach((lvl, idx) => (lvl.editable = idx !== newLevels.length - 1));
|
|
|
+ }
|
|
|
+ authChainLevels.value = newLevels;
|
|
|
+ ElMessage.success('添加成功');
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除授权级别 */
|
|
|
+const handleDeleteAuthLevel = () => {
|
|
|
+ if (authChainLevels.value.length <= 2) {
|
|
|
+ ElMessage.warning('至少保留两级授权');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 删除第一个(0级授权)
|
|
|
+ authChainLevels.value.shift();
|
|
|
+
|
|
|
+ // 重新调整所有级别的标签
|
|
|
+ authChainLevels.value = authChainLevels.value.map((level, index) => ({
|
|
|
+ ...level,
|
|
|
+ label: `${index}级授权`,
|
|
|
+ editable: true
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 仅最后一级不可编辑
|
|
|
+ if (authChainLevels.value.length) {
|
|
|
+ authChainLevels.value.forEach((lvl, idx) => (lvl.editable = idx !== authChainLevels.value.length - 1));
|
|
|
+ }
|
|
|
+
|
|
|
+ ElMessage.success('删除成功');
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取文件名称列表 */
|
|
|
+const getFileNames = (ossIds: string): string[] => {
|
|
|
+ if (!ossIds) return [];
|
|
|
+
|
|
|
+ // 检查缓存
|
|
|
+ if (fileNamesCache.value.has(ossIds)) {
|
|
|
+ return fileNamesCache.value.get(ossIds)!;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在编辑模式下,尝试从 fileDetails 中获取文件名
|
|
|
+ if (isEditMode.value) {
|
|
|
+ const fileRow = fileList.value.find(row => row.fileOssIds === ossIds);
|
|
|
+ if (fileRow && fileRow.fileDetails && fileRow.fileDetails.length > 0) {
|
|
|
+ const fileNames = fileRow.fileDetails.map((detail: any) => detail.originalName);
|
|
|
+ fileNamesCache.value.set(ossIds, fileNames);
|
|
|
+ return fileNames;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 异步加载文件名称(新增模式或缓存未命中时)
|
|
|
+ loadFileNames(ossIds);
|
|
|
+
|
|
|
+ return [];
|
|
|
+};
|
|
|
+
|
|
|
+/** 异步加载文件名称 */
|
|
|
+const loadFileNames = async (ossIds: string) => {
|
|
|
+ try {
|
|
|
+ const res = await listByIds(ossIds);
|
|
|
+ const fileNames = res.data.map((oss: any) => oss.originalName);
|
|
|
+ fileNamesCache.value.set(ossIds, fileNames);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取文件名称失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 监听文件变化,更新文件名称
|
|
|
+watch(
|
|
|
+ () => fileList.value.map(f => f.fileOssIds),
|
|
|
+ (newValues, oldValues) => {
|
|
|
+ newValues.forEach((ossIds, index) => {
|
|
|
+ // 只有当ossIds变化且不为空时才加载
|
|
|
+ if (ossIds && ossIds !== oldValues?.[index]) {
|
|
|
+ // 在编辑模式下,如果已经有缓存的文件详情,就不要重新请求OSS
|
|
|
+ if (isEditMode.value && fileList.value[index].fileDetails && fileList.value[index].fileDetails.length > 0) {
|
|
|
+ console.log('编辑模式:跳过OSS请求,使用已缓存的文件详情');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ loadFileNames(ossIds);
|
|
|
+ // 同时加载文件详情并缓存
|
|
|
+ loadFileDetails(index, ossIds);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ { deep: true }
|
|
|
+);
|
|
|
+
|
|
|
+/** 加载文件详情并缓存 */
|
|
|
+const loadFileDetails = async (fileIndex: number, ossIds: string) => {
|
|
|
+ try {
|
|
|
+ const res = await listByIds(ossIds);
|
|
|
+ fileList.value[fileIndex].fileDetails = res.data || [];
|
|
|
+ console.log(`文件详情已缓存 [${fileList.value[fileIndex].typeName}]:`, res.data);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取文件详情失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 上传文件 */
|
|
|
+const handleUploadFile = (row: any) => {
|
|
|
+ currentFileRow.value = row;
|
|
|
+ fileUploadDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 下载文件 */
|
|
|
+const handleDownloadFile = async (row: any) => {
|
|
|
+ if (!row.fileOssIds) {
|
|
|
+ ElMessage.warning('暂无文件可下载');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await listByIds(row.fileOssIds);
|
|
|
+ if (res.data && res.data.length > 0) {
|
|
|
+ // 下载所有文件
|
|
|
+ res.data.forEach((file: any) => {
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = file.url;
|
|
|
+ link.download = file.originalName;
|
|
|
+ link.target = '_blank';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ });
|
|
|
+ ElMessage.success('开始下载');
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('下载文件失败:', e);
|
|
|
+ ElMessage.error('下载失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除文件 */
|
|
|
+const handleDeleteFile = (row: any) => {
|
|
|
+ ElMessageBox.confirm('确定要删除该资质的所有文件吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ row.fileOssIds = '';
|
|
|
+ // 清除缓存
|
|
|
+ fileNamesCache.value.forEach((value, key) => {
|
|
|
+ if (key.includes(row.fileOssIds)) {
|
|
|
+ fileNamesCache.value.delete(key);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ ElMessage.success('删除成功');
|
|
|
+ }).catch(() => {
|
|
|
+ // 取消删除
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 根据区域ID构建级联选择器的值 */
|
|
|
+const buildCascaderValues = async (areaIds: string[]): Promise<any[]> => {
|
|
|
+ const cascaderValues: any[] = [];
|
|
|
+
|
|
|
+ // 递归寻找属于叶子节点的路径
|
|
|
+ const findLeafPath = (options: any[], targetId: string, currentPath: string[]): boolean => {
|
|
|
+ for (const option of options) {
|
|
|
+ const path = [...currentPath, option.value];
|
|
|
+ if (option.value === targetId) {
|
|
|
+ // 找到了对应的ID,判断是否为叶子节点
|
|
|
+ // 因为 Cascader 的 checkStrictly: false, 父节点的显式勾选会导致级联其下所有节点
|
|
|
+ // 只有是叶子节点(即没有 children),我们才作为有效路径提供给 Cascader 回显
|
|
|
+ if (!option.children || option.children.length === 0) {
|
|
|
+ cascaderValues.push(path);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (option.children && option.children.length > 0) {
|
|
|
+ if (findLeafPath(option.children, targetId, path)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 遍历所有区域ID,仅当它代表叶子节点时才添加路径去激活回显
|
|
|
+ areaIds
|
|
|
+ .map((areaId) => String(areaId).trim())
|
|
|
+ .filter((strId) => strId && isCityCode(strId))
|
|
|
+ .forEach((cityId) => {
|
|
|
+ findLeafPath(areaOptions.value, cityId, []);
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('构建级联选择器值:', { areaIds, cascaderValues });
|
|
|
+ return cascaderValues;
|
|
|
+};
|
|
|
+
|
|
|
+/** 选择区域 */
|
|
|
+const handleSelectArea = () => {
|
|
|
+ areaDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 初始化授权区域选项数据 */
|
|
|
+const initAreaOptions = async () => {
|
|
|
+ try {
|
|
|
+ areaOptions.value = toProvinceCityOptions(regionData as any);
|
|
|
+ console.log('授权区域选项数据加载完成(使用 element-china-area-data):', areaOptions.value.length);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取授权区域数据失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交授权区域 */
|
|
|
+const handleAreaSubmit = async () => {
|
|
|
+ try {
|
|
|
+ areaSubmitLoading.value = true;
|
|
|
+
|
|
|
+ console.log('=== 授权区域提交 ===');
|
|
|
+ console.log('selectedAreas.value:', selectedAreas.value);
|
|
|
+
|
|
|
+ const areaRows = buildAreaRows(selectedAreas.value);
|
|
|
+
|
|
|
+ // 提取所有选中的区域ID(包括省和市的ID),使用后端短编码格式(11、1101)
|
|
|
+ const areaIds: string[] = [];
|
|
|
+ selectedAreas.value.forEach(path => {
|
|
|
+ if (Array.isArray(path)) {
|
|
|
+ // path 是 [省ID, 市ID]
|
|
|
+ console.log('处理路径:', path);
|
|
|
+ path.forEach(id => {
|
|
|
+ console.log('提取ID:', id, '类型:', typeof id);
|
|
|
+ const strId = String(id).trim();
|
|
|
+ if (strId && !areaIds.includes(strId)) {
|
|
|
+ areaIds.push(strId);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ selectedAreaIds.value = areaIds;
|
|
|
+
|
|
|
+ // 更新授权区域列表显示
|
|
|
+ areaList.value = areaRows;
|
|
|
+
|
|
|
+ console.log('选中的授权区域名称:', areaRows);
|
|
|
+ console.log('选中的区域ID列表(用于提交):', selectedAreaIds.value);
|
|
|
+ console.log('=== 授权区域提交完成 ===');
|
|
|
+ ElMessage.success('授权区域设置成功');
|
|
|
+ areaDialogVisible.value = false;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('设置授权区域失败:', e);
|
|
|
+ ElMessage.error('设置失败');
|
|
|
+ } finally {
|
|
|
+ areaSubmitLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const buildAreaRows = (selectedPaths: any[]) => {
|
|
|
+ const provinceMap = new Map<string, Set<string>>();
|
|
|
+
|
|
|
+ const normalizeCityDisplayName = (provinceName: string, cityName: string) => {
|
|
|
+ const p = String(provinceName || '');
|
|
|
+ const c = String(cityName || '');
|
|
|
+ if (!c) return '';
|
|
|
+ if (c === '市辖区') {
|
|
|
+ return p.endsWith('市') ? p : `${p}市`;
|
|
|
+ }
|
|
|
+ return c;
|
|
|
+ };
|
|
|
+
|
|
|
+ selectedPaths.forEach((path) => {
|
|
|
+ if (Array.isArray(path) && path.length >= 2) {
|
|
|
+ const [provinceId, cityId] = path;
|
|
|
+ const provinceName = findRegionNameById(provinceId, areaOptions.value);
|
|
|
+ const province = areaOptions.value.find((p) => p.value === String(provinceId));
|
|
|
+ const cityName = province && cityId ? findRegionNameById(cityId, province.children || []) : '';
|
|
|
+
|
|
|
+ if (!provinceName) return;
|
|
|
+ if (!provinceMap.has(provinceName)) {
|
|
|
+ provinceMap.set(provinceName, new Set());
|
|
|
+ }
|
|
|
+ const displayCityName = normalizeCityDisplayName(provinceName, cityName);
|
|
|
+ if (displayCityName) {
|
|
|
+ provinceMap.get(provinceName)!.add(displayCityName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return Array.from(provinceMap.entries()).map(([province, cities]) => {
|
|
|
+ return {
|
|
|
+ province,
|
|
|
+ city: Array.from(cities).join(',')
|
|
|
+ };
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 从级联选择器的值中提取区域数据 */
|
|
|
+const extractRegionData = (selectedPaths: any[]) => {
|
|
|
+ // 用于存储省-市的映射关系
|
|
|
+ const provinceMap = new Map<string, Set<string>>();
|
|
|
+
|
|
|
+ selectedPaths.forEach(path => {
|
|
|
+ if (Array.isArray(path) && path.length >= 2) {
|
|
|
+ const [provinceId, cityId] = path;
|
|
|
+
|
|
|
+ // 查找对应的名称(通过value查找)
|
|
|
+ const provinceName = findRegionNameById(provinceId, areaOptions.value);
|
|
|
+ const province = areaOptions.value.find(p => p.value === provinceId);
|
|
|
+ const cityName = province && cityId ? findRegionNameById(cityId, province.children || []) : '';
|
|
|
+
|
|
|
+ if (provinceName) {
|
|
|
+ if (!provinceMap.has(provinceName)) {
|
|
|
+ provinceMap.set(provinceName, new Set());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 直辖市的处理(市辖区转为原来的名称)
|
|
|
+ if (cityName && cityName !== '市辖区') {
|
|
|
+ provinceMap.get(provinceName)!.add(cityName);
|
|
|
+ } else if (cityName === '市辖区') {
|
|
|
+ provinceMap.get(provinceName)!.add(provinceName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成省份和城市字符串
|
|
|
+ const provinces: string[] = [];
|
|
|
+ const cities: string[] = [];
|
|
|
+
|
|
|
+ provinceMap.forEach((citySet, provinceName) => {
|
|
|
+ provinces.push(provinceName);
|
|
|
+ cities.push(Array.from(citySet).join(','));
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ provinces: provinces.join(','),
|
|
|
+ cities: cities.join(';')
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/** 根据value查找区域名称 */
|
|
|
+const findRegionNameById = (id: string | number, regions: any[]): string => {
|
|
|
+ const targetId = String(id);
|
|
|
+ const region = regions.find(r => r.value === targetId);
|
|
|
+ return region ? region.label : '';
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交 */
|
|
|
+const handleSubmit = async () => {
|
|
|
+ try {
|
|
|
+ // 验证必填项
|
|
|
+ if (!formData.value.brandId || !formData.value.brandName) {
|
|
|
+ ElMessage.warning('请选择品牌');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 编辑模式下跳过分类验证,因为分类是锁死的
|
|
|
+ if (!isEditMode.value) {
|
|
|
+ if (!formData.value.category1 || !formData.value.category2 || !formData.value.category3) {
|
|
|
+ ElMessage.warning('请选择完整的分类');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!userStore.supplierId) {
|
|
|
+ ElMessage.error('供应商ID不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 收集所有分类数据
|
|
|
+ const allCategories = [
|
|
|
+ {
|
|
|
+ category1: formData.value.category1,
|
|
|
+ category2: formData.value.category2,
|
|
|
+ category3: formData.value.category3
|
|
|
+ },
|
|
|
+ ...extraCategoryRows.value.map(row => ({
|
|
|
+ category1: formData.value.category1,
|
|
|
+ category2: row.category2,
|
|
|
+ category3: row.category3
|
|
|
+ }))
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 提取所有三级分类ID(只传三级分类ID的列表,并去重)
|
|
|
+ const categoryIds = [...new Set(
|
|
|
+ allCategories
|
|
|
+ .map(cat => cat.category3)
|
|
|
+ .filter(id => id) // 过滤掉空值
|
|
|
+ )];
|
|
|
+
|
|
|
+ // 验证是否有重复的分类
|
|
|
+ if (categoryIds.length !== allCategories.filter(cat => cat.category3).length) {
|
|
|
+ console.warn('检测到重复的分类选择,已自动去重');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建授权区域字符串(使用ID,用逗号分隔)
|
|
|
+ const authorizedArea = selectedAreaIds.value.join(',');
|
|
|
+
|
|
|
+ console.log('=== 构建授权区域 ===');
|
|
|
+ console.log('selectedAreaIds.value:', selectedAreaIds.value);
|
|
|
+ console.log('authorizedArea (提交给后端):', authorizedArea);
|
|
|
+ console.log('类型检查 - 是否包含数字:', selectedAreaIds.value.map(id => ({ id, type: typeof id })));
|
|
|
+
|
|
|
+ // 构建授权链路字符串(从0级到最高级,用逗号分隔)
|
|
|
+ const brandLicensor = authChainLevels.value
|
|
|
+ .map(level => level.value)
|
|
|
+ .filter(value => value) // 过滤掉空值
|
|
|
+ .join(',');
|
|
|
+
|
|
|
+ // 构建资质文件集合(使用缓存的文件详情)
|
|
|
+ const qualificationFiles: QualificationFileForm[] = [];
|
|
|
+
|
|
|
+ for (const file of fileList.value) {
|
|
|
+ if (file.fileOssIds && file.fileDetails.length > 0) {
|
|
|
+ // 使用缓存的文件详情,无需再次请求
|
|
|
+ file.fileDetails.forEach((ossFile: any) => {
|
|
|
+ qualificationFiles.push({
|
|
|
+ name: file.typeName, // 资质类型名称(商标注册证、品牌授权书、质检报告)
|
|
|
+ fileName: ossFile.originalName, // 文件名称
|
|
|
+ fileType: ossFile.fileSuffix || '', // 文件类型
|
|
|
+ fileUrl: ossFile.url, // 文件URL
|
|
|
+ endTime: file.expireDate ? new Date(file.expireDate).toISOString() : '' // 资质到期日期
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('使用缓存的文件详情,无需等待OSS请求');
|
|
|
+
|
|
|
+ // 构建提交数据
|
|
|
+ const submitData: any = {
|
|
|
+ supplierId: userStore.supplierId,
|
|
|
+ supplierNo: userStore.supplierNo,
|
|
|
+ brandId: formData.value.brandId,
|
|
|
+ brandNo: formData.value.brandNo,
|
|
|
+ brandName: formData.value.brandName,
|
|
|
+ brandLogo: formData.value.brandLogo,
|
|
|
+ brandRegistrant: formData.value.brandRegistrant,
|
|
|
+ authorizeType: formData.value.authorizeTypeId, // 授权类型ID
|
|
|
+ authorizeLevel: formData.value.authorizeLevel, // 授权等级
|
|
|
+ categoryIds: categoryIds, // 三级分类ID列表
|
|
|
+ authorizedArea: authorizedArea, // 授权地址(区域ID列表)
|
|
|
+ brandLicensor: brandLicensor, // 授权链路(授权人列表)
|
|
|
+ qualificationFiles: qualificationFiles // 资质文件集合
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('提交数据:', submitData);
|
|
|
+ console.log('三级分类ID列表:', categoryIds);
|
|
|
+ console.log('授权地址:', authorizedArea);
|
|
|
+ console.log('授权链路:', brandLicensor);
|
|
|
+ console.log('资质文件集合:', qualificationFiles);
|
|
|
+
|
|
|
+ // 调用API(根据模式调用不同的接口)
|
|
|
+ if (isEditMode.value) {
|
|
|
+ // 编辑模式:调用更新接口
|
|
|
+ await updateSupplierauthorize({ ...submitData, id: editId.value });
|
|
|
+ ElMessage.success('更新成功');
|
|
|
+ } else {
|
|
|
+ // 新增模式:调用新增接口
|
|
|
+ await addSupplierauthorize(submitData);
|
|
|
+ ElMessage.success('提交成功');
|
|
|
+ }
|
|
|
+
|
|
|
+ router.back();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('提交失败:', error);
|
|
|
+ ElMessage.error('提交失败,请重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ console.log('=== Edit页面初始化 ===');
|
|
|
+ console.log('route.query:', route.query);
|
|
|
+ console.log('route.query.id:', route.query.id);
|
|
|
+
|
|
|
+ // 检查是否为编辑模式
|
|
|
+ if (route.query.id) {
|
|
|
+ editId.value = route.query.id as string;
|
|
|
+ isEditMode.value = true;
|
|
|
+ console.log('✓ 编辑模式,ID:', editId.value);
|
|
|
+ console.log('✓ isEditMode.value:', isEditMode.value);
|
|
|
+
|
|
|
+ // 编辑模式:并行加载基础数据和详情数据
|
|
|
+ await Promise.all([
|
|
|
+ getBrandList(),
|
|
|
+ getAuthorizeTypeList(),
|
|
|
+ getCategory1List(),
|
|
|
+ initAreaOptions(),
|
|
|
+ loadDetailData() // 详情数据也并行加载
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ console.log('✓ 新增模式');
|
|
|
+ console.log('✓ isEditMode.value:', isEditMode.value);
|
|
|
+
|
|
|
+ // 新增模式:只加载基础数据
|
|
|
+ await Promise.all([
|
|
|
+ getBrandList(),
|
|
|
+ getAuthorizeTypeList(),
|
|
|
+ getCategory1List(),
|
|
|
+ initAreaOptions()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('=== Edit页面初始化完成 ===');
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.app-container {
|
|
|
+ background: #f0f2f5;
|
|
|
+ min-height: 100vh;
|
|
|
+}
|
|
|
+
|
|
|
+.page-header {
|
|
|
+ background: #fff;
|
|
|
+ padding: 16px 24px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ border-bottom: 1px solid #e8e8e8;
|
|
|
+}
|
|
|
+
|
|
|
+.back-icon {
|
|
|
+ font-size: 18px;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-right: 12px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.back-icon:hover {
|
|
|
+ color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.page-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.form-section {
|
|
|
+ background: #fff;
|
|
|
+ margin: 20px;
|
|
|
+ padding: 24px;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ padding-bottom: 12px;
|
|
|
+ border-bottom: 1px solid #e8e8e8;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-form {
|
|
|
+ margin-bottom: 30px;
|
|
|
+}
|
|
|
+
|
|
|
+.extra-category-row {
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.file-section,
|
|
|
+.area-section {
|
|
|
+ margin-top: 30px;
|
|
|
+}
|
|
|
+
|
|
|
+.file-title,
|
|
|
+.area-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-tip {
|
|
|
+ text-align: center;
|
|
|
+ padding: 40px;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.submit-section {
|
|
|
+ margin-top: 30px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.file-name-list {
|
|
|
+ text-align: left;
|
|
|
+ padding: 8px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.file-name-item {
|
|
|
+ padding: 4px 0;
|
|
|
+ color: #409eff;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+.file-actions {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-chain-container {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-chain-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-chain-custom-table {
|
|
|
+ width: 100%;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ border-radius: 4px;
|
|
|
+ overflow-x: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-chain-header {
|
|
|
+ display: flex;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-chain-row {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-chain-cell {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 200px;
|
|
|
+ padding: 12px;
|
|
|
+ text-align: center;
|
|
|
+ border-right: 1px solid #ebeef5;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-chain-cell:last-child {
|
|
|
+ border-right: none;
|
|
|
+}
|
|
|
+
|
|
|
+.header-cell {
|
|
|
+ font-weight: bold;
|
|
|
+ color: #909399;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 只读输入框样式 - 更美观的设计 */
|
|
|
+.readonly-input :deep(.el-input__wrapper) {
|
|
|
+ background: var(--el-input-bg-color) !important;
|
|
|
+ border: 1px solid var(--el-border-color) !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+ cursor: default !important;
|
|
|
+}
|
|
|
+
|
|
|
+.readonly-input :deep(.el-input__inner) {
|
|
|
+ background: transparent !important;
|
|
|
+ color: var(--el-text-color-regular) !important;
|
|
|
+ font-weight: 400 !important;
|
|
|
+
|
|
|
+ /* 文字居中显示 */
|
|
|
+ text-align: left !important;
|
|
|
+}
|
|
|
+
|
|
|
+.readonly-input :deep(.el-input__wrapper):hover {
|
|
|
+ border-color: var(--el-border-color) !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+}
|
|
|
+
|
|
|
+.readonly-input :deep(.el-input__wrapper):focus-within {
|
|
|
+ border-color: var(--el-border-color) !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-form :deep(.el-input.is-disabled .el-input__wrapper),
|
|
|
+.auth-form :deep(.el-select .el-input.is-disabled .el-input__wrapper) {
|
|
|
+ cursor: default;
|
|
|
+}
|
|
|
+
|
|
|
+.readonly-not-allowed :deep(.el-input__wrapper) {
|
|
|
+ cursor: not-allowed !important;
|
|
|
+ pointer-events: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.readonly-not-allowed :deep(.el-input__inner) {
|
|
|
+ cursor: default !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 分类区域样式 */
|
|
|
+.category-section {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ padding: 16px;
|
|
|
+ background: #fafbfc;
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #e1e4e8;
|
|
|
+}
|
|
|
+
|
|
|
+.section-label {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #24292e;
|
|
|
+}
|
|
|
+</style>
|