9
0

3 Коммиты d17d07ed16 ... 5a5c906515

Автор SHA1 Сообщение Дата
  Lijingyang 5a5c906515 Merge branch 'ljy' 1 месяц назад
  Lijingyang b11ff4ff79 feat(api): 添加多个业务模块的API接口和服务 1 месяц назад
  Lijingyang 737ed6ecdb feat(supplier): 新增供应商授权详情页面 1 месяц назад

+ 41 - 0
src/api/company/revenueExpense/index.ts

@@ -0,0 +1,41 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { RevenueExpenseVO, RevenueExpenseForm, RevenueExpenseQuery } from '@/api/company/revenueExpense/types';
+
+export const listRevenueExpense = (query?: RevenueExpenseQuery): AxiosPromise<RevenueExpenseVO[]> => {
+  return request({
+    url: '/company/revenueExpense/list',
+    method: 'get',
+    params: query
+  });
+};
+
+export const getRevenueExpense = (id: string | number): AxiosPromise<RevenueExpenseVO> => {
+  return request({
+    url: '/company/revenueExpense/' + id,
+    method: 'get'
+  });
+};
+
+export const addRevenueExpense = (data: RevenueExpenseForm) => {
+  return request({
+    url: '/company/revenueExpense',
+    method: 'post',
+    data
+  });
+};
+
+export const updateRevenueExpense = (data: RevenueExpenseForm) => {
+  return request({
+    url: '/company/revenueExpense',
+    method: 'put',
+    data
+  });
+};
+
+export const delRevenueExpense = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/company/revenueExpense/' + id,
+    method: 'delete'
+  });
+};

+ 18 - 0
src/api/company/revenueExpense/types.ts

@@ -0,0 +1,18 @@
+export interface RevenueExpenseVO {
+  id?: string | number;
+  expenseCode?: string;
+  expenseName?: string;
+  expenseFlag?: string;
+  remark?: string;
+}
+
+export interface RevenueExpenseForm extends RevenueExpenseVO {}
+
+export interface RevenueExpenseQuery {
+  pageNum?: number;
+  pageSize?: number;
+  expenseCode?: string;
+  expenseName?: string;
+  expenseFlag?: string;
+  params?: Record<string, any>;
+}

+ 41 - 0
src/api/product/extend/index.ts

@@ -0,0 +1,41 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ExtendVO, ExtendForm, ExtendQuery } from '@/api/product/extend/types';
+
+export const listExtend = (query?: ExtendQuery): AxiosPromise<ExtendVO[]> => {
+  return request({
+    url: '/product/extend/list',
+    method: 'get',
+    params: query
+  });
+};
+
+export const getExtend = (id: string | number): AxiosPromise<ExtendVO> => {
+  return request({
+    url: '/product/extend/' + id,
+    method: 'get'
+  });
+};
+
+export const addExtend = (data: ExtendForm) => {
+  return request({
+    url: '/product/extend',
+    method: 'post',
+    data
+  });
+};
+
+export const updateExtend = (data: ExtendForm) => {
+  return request({
+    url: '/product/extend',
+    method: 'put',
+    data
+  });
+};
+
+export const delExtend = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/extend/' + id,
+    method: 'delete'
+  });
+};

+ 92 - 0
src/api/product/extend/types.ts

@@ -0,0 +1,92 @@
+export interface ExtendVO {
+  productId?: string | number;
+  promotionTitle?: string;
+  invoiceName?: string;
+  invoiceType?: string | number;
+  specificationsCode?: string;
+  barCoding?: string;
+  productDescription?: string;
+  productWeight?: string | number;
+  weightUnit?: string;
+  productVolume?: string | number;
+  volumeUnit?: string;
+  afterSalesService?: string;
+  serviceGuarantee?: string;
+  isInstallService?: string | number;
+  installAmount?: string | number;
+  distributionPrice?: string | number;
+  standardSizes?: string;
+  gramWeight?: string | number;
+  opacity?: string | number;
+  isCustomize?: string | number;
+  customDescription?: string;
+  productProfit?: string | number;
+  reportRequire?: string;
+  reviewComments?: string;
+  supplierNo?: string;
+  pushStatus?: string | number;
+  dataSource?: string;
+  invoiceSpecs?: string;
+  increment?: string | number;
+  purchaseNo?: string;
+  purchaseName?: string;
+  supplierName?: string;
+  purchaseManagerNo?: string;
+  purchaseManagerName?: string;
+  referenceLink?: string;
+  salesVolume?: string | number;
+  deliveryTime?: string;
+  pitTime?: string;
+  createSupplier?: string;
+  otherInfo?: string;
+  platformCode?: string;
+  remark?: string;
+}
+
+export interface ExtendForm extends ExtendVO {}
+
+export interface ExtendQuery {
+  pageNum?: number;
+  pageSize?: number;
+  promotionTitle?: string;
+  invoiceName?: string;
+  invoiceType?: string | number;
+  specificationsCode?: string;
+  barCoding?: string;
+  productDescription?: string;
+  productWeight?: string | number;
+  weightUnit?: string;
+  productVolume?: string | number;
+  volumeUnit?: string;
+  afterSalesService?: string;
+  serviceGuarantee?: string;
+  isInstallService?: string | number;
+  installAmount?: string | number;
+  distributionPrice?: string | number;
+  standardSizes?: string;
+  gramWeight?: string | number;
+  opacity?: string | number;
+  isCustomize?: string | number;
+  customDescription?: string;
+  productProfit?: string | number;
+  reportRequire?: string;
+  reviewComments?: string;
+  supplierNo?: string;
+  pushStatus?: string | number;
+  dataSource?: string;
+  invoiceSpecs?: string;
+  increment?: string | number;
+  purchaseNo?: string;
+  purchaseName?: string;
+  supplierName?: string;
+  purchaseManagerNo?: string;
+  purchaseManagerName?: string;
+  referenceLink?: string;
+  salesVolume?: string | number;
+  deliveryTime?: string;
+  pitTime?: string;
+  createSupplier?: string;
+  otherInfo?: string;
+  platformCode?: string;
+  params?: Record<string, any>;
+}

+ 41 - 0
src/api/product/lable/index.ts

@@ -0,0 +1,41 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { LableVO, LableForm, LableQuery } from '@/api/product/lable/types';
+
+export const listLable = (query?: LableQuery): AxiosPromise<LableVO[]> => {
+  return request({
+    url: '/product/lable/list',
+    method: 'get',
+    params: query
+  });
+};
+
+export const getLable = (id: string | number): AxiosPromise<LableVO> => {
+  return request({
+    url: '/product/lable/' + id,
+    method: 'get'
+  });
+};
+
+export const addLable = (data: LableForm) => {
+  return request({
+    url: '/product/lable',
+    method: 'post',
+    data
+  });
+};
+
+export const updateLable = (data: LableForm) => {
+  return request({
+    url: '/product/lable',
+    method: 'put',
+    data
+  });
+};
+
+export const delLable = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/lable/' + id,
+    method: 'delete'
+  });
+};

+ 14 - 0
src/api/product/lable/types.ts

@@ -0,0 +1,14 @@
+export interface LableVO {
+  id?: string | number;
+  productLabelName?: string;
+  productQuantity?: number;
+}
+
+export interface LableForm extends LableVO {}
+
+export interface LableQuery {
+  pageNum?: number;
+  pageSize?: number;
+  productLabelName?: string;
+  params?: Record<string, any>;
+}

+ 26 - 0
src/api/product/pool/index.ts

@@ -0,0 +1,26 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PoolVO, PoolQuery, PoolReviewForm } from '@/api/product/pool/types';
+
+export const listPool = (query?: PoolQuery): AxiosPromise<PoolVO[]> => {
+  return request({
+    url: '/product/pool/list',
+    method: 'get',
+    params: query
+  });
+};
+
+export const getPool = (id: string | number): AxiosPromise<PoolVO> => {
+  return request({
+    url: '/product/pool/' + id,
+    method: 'get'
+  });
+};
+
+export const updatePool = (data: PoolReviewForm) => {
+  return request({
+    url: '/product/pool',
+    method: 'put',
+    data
+  });
+};

+ 40 - 0
src/api/product/pool/types.ts

@@ -0,0 +1,40 @@
+export interface PoolVO {
+  id?: string | number;
+  poolNo?: string;
+  itemId?: string | number;
+  categoryId?: string | number;
+  type?: number;
+  name?: string;
+  isShow?: string | number;
+  productReviewStatus?: string;
+  reviewReason?: string;
+  createBy?: string;
+  reviewBy?: string;
+  remark?: string;
+  waitApplyCount?: number;
+  waitReviewCount?: number;
+  approvedCount?: number;
+  rejectedCount?: number;
+}
+
+export interface PoolReviewForm {
+  id?: string | number;
+  itemId?: string | number;
+  categoryId?: string | number;
+  type?: number;
+  productReviewStatus?: string;
+  reviewReason?: string;
+}
+
+export interface PoolQuery {
+  pageNum?: number;
+  pageSize?: number;
+  itemId?: string | number;
+  categoryId?: string | number;
+  type?: number;
+  name?: string;
+  productReviewStatus?: string;
+  createBy?: string;
+  reviewBy?: string;
+  params?: Record<string, any>;
+}

+ 41 - 0
src/api/product/recommend/index.ts

@@ -0,0 +1,41 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { RecommendVO, RecommendForm, RecommendQuery } from '@/api/product/recommend/types';
+
+export const listRecommend = (query?: RecommendQuery): AxiosPromise<RecommendVO[]> => {
+  return request({
+    url: '/product/recommend/list',
+    method: 'get',
+    params: query
+  });
+};
+
+export const getRecommend = (id: string | number): AxiosPromise<RecommendVO> => {
+  return request({
+    url: '/product/recommend/' + id,
+    method: 'get'
+  });
+};
+
+export const addRecommend = (data: RecommendForm) => {
+  return request({
+    url: '/product/recommend',
+    method: 'post',
+    data
+  });
+};
+
+export const updateRecommend = (data: RecommendForm) => {
+  return request({
+    url: '/product/recommend',
+    method: 'put',
+    data
+  });
+};
+
+export const delRecommend = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/recommend/' + id,
+    method: 'delete'
+  });
+};

+ 24 - 0
src/api/product/recommend/types.ts

@@ -0,0 +1,24 @@
+export interface RecommendVO {
+  id?: string | number;
+  recommendNo?: string;
+  recommendName?: string;
+  recommendDescribe?: string;
+  isShow?: string | number;
+  recommendCoverphoto?: string;
+  remark?: string;
+  platformCode?: string;
+}
+
+export interface RecommendForm extends RecommendVO {}
+
+export interface RecommendQuery {
+  pageNum?: number;
+  pageSize?: number;
+  recommendNo?: string;
+  recommendName?: string;
+  recommendDescribe?: string;
+  isShow?: string | number;
+  recommendCoverphoto?: string;
+  platformCode?: string;
+  params?: Record<string, any>;
+}

+ 63 - 0
src/api/supplier/authorizetypeLevel/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { AuthorizetypeLevelVO, AuthorizetypeLevelForm, AuthorizetypeLevelQuery } from '@/api/supplier/authorizetypeLevel/types';
+
+/**
+ * 查询供应商授权等级和授权类型列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listAuthorizetypeLevel = (query?: AuthorizetypeLevelQuery): AxiosPromise<AuthorizetypeLevelVO[]> => {
+  return request({
+    url: '/system/authorizetypeLevel/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询供应商授权等级和授权类型详细
+ * @param id
+ */
+export const getAuthorizetypeLevel = (id: string | number): AxiosPromise<AuthorizetypeLevelVO> => {
+  return request({
+    url: '/system/authorizetypeLevel/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增供应商授权等级和授权类型
+ * @param data
+ */
+export const addAuthorizetypeLevel = (data: AuthorizetypeLevelForm) => {
+  return request({
+    url: '/system/authorizetypeLevel',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改供应商授权等级和授权类型
+ * @param data
+ */
+export const updateAuthorizetypeLevel = (data: AuthorizetypeLevelForm) => {
+  return request({
+    url: '/system/authorizetypeLevel',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除供应商授权等级和授权类型
+ * @param id
+ */
+export const delAuthorizetypeLevel = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/system/authorizetypeLevel/' + id,
+    method: 'delete'
+  });
+};

+ 71 - 0
src/api/supplier/authorizetypeLevel/types.ts

@@ -0,0 +1,71 @@
+export interface AuthorizetypeLevelVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 授权类型
+   */
+  authorizeType: string;
+
+  /**
+   * 授权等级
+   */
+  authorizeLevel: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+}
+
+export interface AuthorizetypeLevelForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 授权类型
+   */
+  authorizeType?: string;
+
+  /**
+   * 授权等级
+   */
+  authorizeLevel?: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+}
+
+export interface AuthorizetypeLevelQuery extends PageQuery {
+
+  /**
+   * 授权类型
+   */
+  authorizeType?: string;
+
+  /**
+   * 授权等级
+   */
+  authorizeLevel?: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 454 - 0
src/views/product/brandexam/index.vue

@@ -0,0 +1,454 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="品牌名称" prop="brandName">
+              <el-input v-model="queryParams.brandName" placeholder="请输入品牌名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="品牌编号" prop="brandNo">
+              <el-input v-model="queryParams.brandNo" placeholder="请输入品牌编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <div class="flex items-center justify-between">
+          <div class="font-bold">品牌审核信息列表</div>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </div>
+      </template>
+
+      <el-table v-loading="loading" border :data="brandList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="品牌编号" align="center" prop="brandNo" width="120" />
+        <el-table-column label="品牌名称" align="center" prop="brandName" />
+        <el-table-column label="品牌LOGO" align="center" prop="brandLogo" width="120">
+          <template #default="scope">
+            <el-image
+              v-if="scope.row.brandLogo"
+              :src="scope.row.brandLogo"
+              :preview-src-list="[scope.row.brandLogo]"
+              preview-teleported
+              fit="cover"
+              style="width: 48px; height: 48px"
+            />
+            <span v-else></span>
+          </template>
+        </el-table-column>
+        <el-table-column label="创建时间" align="center" prop="createTime" />
+        <el-table-column label="状态" align="center" prop="brandStatus" width="120">
+          <template #default="scope">
+            <span>{{ getBrandStatusLabel(scope.row) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="审核状态" align="center" width="120">
+          <template #default="scope">
+            <span>{{ getAuditStatusLabel(scope.row) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
+          <template #default="scope">
+            <div class="action-btns flex items-center justify-center gap-1 whitespace-nowrap">
+              <el-button link type="primary" @click="handleView(scope.row)" v-hasPermi="['product:brand:query']">查看</el-button>
+              <el-button link type="primary" @click="handleEdit(scope.row)" v-hasPermi="['product:brand:edit']">编辑</el-button>
+              <el-button link type="primary" @click="openAuditDialog(scope.row, 'approve')">审核</el-button>
+              <el-button link type="danger" @click="openAuditDialog(scope.row, 'reject')">驳回</el-button>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品品牌信息对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="brandFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="品牌编号" prop="brandNo">
+          <el-input v-model="form.brandNo" placeholder="请输入品牌编号" />
+        </el-form-item>
+        <el-form-item label="品牌中文名称" prop="brandName">
+          <el-input v-model="form.brandName" placeholder="请输入品牌中文名称" />
+        </el-form-item>
+        <el-form-item label="品牌首字母缩写" prop="brandInitials">
+          <el-input v-model="form.brandInitials" placeholder="请输入品牌首字母缩写" />
+        </el-form-item>
+        <el-form-item label="品牌英文名称" prop="brandEnglishName">
+          <el-input v-model="form.brandEnglishName" placeholder="请输入品牌英文名称" />
+        </el-form-item>
+        <el-form-item label="推荐值" prop="recommendValue">
+          <el-input v-model="form.recommendValue" placeholder="请输入推荐值" />
+        </el-form-item>
+        <el-form-item label="品牌Logo图片路径或URL" prop="brandLogo">
+          <el-input v-model="form.brandLogo" placeholder="请输入品牌Logo图片路径或URL" />
+        </el-form-item>
+        <el-form-item label="品牌标题" prop="brandTitle">
+          <el-input v-model="form.brandTitle" placeholder="请输入品牌标题" />
+        </el-form-item>
+        <el-form-item label="品牌大图" prop="brandBigImage">
+          <image-upload v-model="form.brandBigImage"/>
+        </el-form-item>
+        <el-form-item label="品牌故事" prop="brandStory">
+            <el-input v-model="form.brandStory" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="是否显示" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示" />
+        </el-form-item>
+        <el-form-item label="品牌注册人" prop="brandRegistrant">
+          <el-input v-model="form.brandRegistrant" placeholder="请输入品牌注册人" />
+        </el-form-item>
+        <el-form-item label="许可证编号" prop="license">
+          <el-input v-model="form.license" placeholder="请输入许可证编号" />
+        </el-form-item>
+        <el-form-item label="注册证书编号" prop="registrationCertificate">
+          <el-input v-model="form.registrationCertificate" placeholder="请输入注册证书编号" />
+        </el-form-item>
+        <el-form-item label="证书/许可过期时间" prop="expireTime">
+          <el-date-picker clearable
+            v-model="form.expireTime"
+            type="datetime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择证书/许可过期时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="品牌描述" prop="brandDescribe">
+            <el-input v-model="form.brandDescribe" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="展示位置" prop="position">
+          <el-input v-model="form.position" placeholder="请输入展示位置" />
+        </el-form-item>
+        <el-form-item label="关注度/收藏数" prop="care">
+          <el-input v-model="form.care" placeholder="请输入关注度/收藏数" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <el-dialog v-model="auditDialogVisible" :title="auditDialogTitle" width="520px" append-to-body>
+      <el-form label-width="90px">
+        <el-form-item label="审核意见" required>
+          <el-input v-model="auditRemark" type="textarea" :rows="4" placeholder="请输入审核意见" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="auditLoading" type="primary" @click="submitAudit">确 定</el-button>
+          <el-button @click="auditDialogVisible = false">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Brand" lang="ts">
+import { listBrand, getBrand, delBrand, addBrand, updateBrand } from '@/api/product/brand';
+import { BrandVO, BrandQuery, BrandForm } from '@/api/product/brand/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+
+const { brand_status } = toRefs<any>(proxy?.useDict('brand_status'));
+
+const brandList = ref<BrandVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const brandFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BrandForm = {
+  id: undefined,
+  brandNo: undefined,
+  brandName: undefined,
+  brandInitials: undefined,
+  brandEnglishName: undefined,
+  recommendValue: undefined,
+  brandLogo: undefined,
+  brandTitle: undefined,
+  brandBigImage: undefined,
+  brandStory: undefined,
+  isShow: undefined,
+  brandRegistrant: undefined,
+  license: undefined,
+  registrationCertificate: undefined,
+  expireTime: undefined,
+  brandDescribe: undefined,
+  position: undefined,
+  care: undefined,
+  dataSource: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<BrandForm, BrandQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    brandNo: undefined,
+    brandName: undefined,
+    brandInitials: undefined,
+    brandEnglishName: undefined,
+    recommendValue: undefined,
+    brandLogo: undefined,
+    brandTitle: undefined,
+    brandBigImage: undefined,
+    brandStory: undefined,
+    isShow: undefined,
+    brandRegistrant: undefined,
+    license: undefined,
+    registrationCertificate: undefined,
+    expireTime: undefined,
+    brandDescribe: undefined,
+    position: undefined,
+    care: undefined,
+    dataSource: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    brandInitials: [
+      { required: true, message: "品牌首字母缩写不能为空", trigger: "blur" }
+    ],
+    brandEnglishName: [
+      { required: true, message: "品牌英文名称不能为空", trigger: "blur" }
+    ],
+    recommendValue: [
+      { required: true, message: "推荐值不能为空", trigger: "blur" }
+    ],
+    brandLogo: [
+      { required: true, message: "品牌Logo图片路径或URL不能为空", trigger: "blur" }
+    ],
+    brandTitle: [
+      { required: true, message: "品牌标题不能为空", trigger: "blur" }
+    ],
+    brandBigImage: [
+      { required: true, message: "品牌大图不能为空", trigger: "blur" }
+    ],
+    brandStory: [
+      { required: true, message: "品牌故事不能为空", trigger: "blur" }
+    ],
+    isShow: [
+      { required: true, message: "是否显示不能为空", trigger: "blur" }
+    ],
+    brandRegistrant: [
+      { required: true, message: "品牌注册人不能为空", trigger: "blur" }
+    ],
+    license: [
+      { required: true, message: "许可证编号不能为空", trigger: "blur" }
+    ],
+    registrationCertificate: [
+      { required: true, message: "注册证书编号不能为空", trigger: "blur" }
+    ],
+    expireTime: [
+      { required: true, message: "证书/许可过期时间不能为空", trigger: "blur" }
+    ],
+    brandDescribe: [
+      { required: true, message: "品牌描述不能为空", trigger: "blur" }
+    ],
+    position: [
+      { required: true, message: "展示位置不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getBrandStatusLabel = (row: any) => {
+  const val = row?.brandStatus;
+  const hit = (brand_status.value || []).find((d: any) => String(d.value) === String(val));
+  return hit?.label ?? (val === undefined || val === null || val === '' ? '' : String(val));
+};
+
+const getAuditStatusLabel = (row: any) => {
+  const val = row?.brandStatus;
+  if (String(val) === '0') return '审核中';
+  if (String(val) === '1' || String(val) === '3') return '审核完成';
+  return '';
+};
+
+const auditDialogVisible = ref(false);
+const auditLoading = ref(false);
+const auditAction = ref<'approve' | 'reject'>('approve');
+const auditRowId = ref<string | number>();
+const auditRemark = ref('');
+
+const auditDialogTitle = computed(() => (auditAction.value === 'approve' ? '审核' : '驳回'));
+
+const openAuditDialog = (row: any, action: 'approve' | 'reject') => {
+  auditAction.value = action;
+  auditRowId.value = row?.id;
+  auditRemark.value = '';
+  auditDialogVisible.value = true;
+};
+
+const submitAudit = async () => {
+  if (!auditRowId.value) return;
+  if (!auditRemark.value) {
+    proxy?.$modal.msgError('请输入审核意见');
+    return;
+  }
+  auditLoading.value = true;
+  try {
+    await updateBrand({ id: auditRowId.value, remark: auditRemark.value, brandStatus: auditAction.value === 'approve' ? 1 : 3 } as any);
+    proxy?.$modal.msgSuccess('操作成功');
+    auditDialogVisible.value = false;
+    await getList();
+  } finally {
+    auditLoading.value = false;
+  }
+};
+
+/** 查询产品品牌信息列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listBrand(queryParams.value);
+  brandList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  brandFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BrandVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push({
+    path: '/product/brand/edit',
+    query: {
+      type: 'add'
+    }
+  });
+}
+
+/** 查看按钮操作 */
+const handleView = async (row?: BrandVO) => {
+  const _id = row?.id || ids.value[0];
+  if (!_id) return;
+  router.push({
+    path: '/product/brand/edit',
+    query: {
+      id: _id,
+      type: 'view'
+    }
+  });
+}
+
+/** 编辑按钮操作 */
+const handleEdit = async (row?: BrandVO) => {
+  const _id = row?.id || ids.value[0];
+  if (!_id) return;
+  router.push({
+    path: '/product/brand/edit',
+    query: {
+      id: _id,
+      type: 'edit'
+    }
+  });
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  brandFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateBrand(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addBrand(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BrandVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品品牌信息编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delBrand(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/brand/export', {
+    ...queryParams.value
+  }, `brand_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped>
+.action-btns :deep(.el-button + .el-button) {
+  margin-left: 0;
+}
+</style>

+ 1738 - 0
src/views/supplier/supplierexam/detail.vue

@@ -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>

+ 1812 - 0
src/views/supplier/supplierexam/edit.vue

@@ -0,0 +1,1812 @@
+<template>
+  <div class="app-container">
+    <!-- 页面头部 -->
+    <div class="page-header">
+      <el-icon class="back-icon" @click="goBack"><ArrowLeft /></el-icon>
+      <span class="page-title">{{ isEditMode ? '修改产品线授权' : '新增产品线授权' }}</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 class="auth-chain-actions">
+              <el-button type="primary" @click="handleAddAuthLevel" :disabled="authChainLevels.length >= 5">添加品牌授权人</el-button>
+              <el-button type="danger" @click="handleDeleteAuthLevel" :disabled="authChainLevels.length <= 2">删除</el-button>
+            </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">
+                <el-button type="primary" link @click="handleUploadFile(scope.row)">上传文件</el-button>
+                <template v-if="scope.row.fileOssIds">
+                  <el-button type="primary" link @click="handleDownloadFile(scope.row)">下载</el-button>
+                  <el-button type="danger" link @click="handleDeleteFile(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>
+          <el-button type="primary" @click="handleSelectArea">选择区域</el-button>
+        </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 class="submit-section">
+        <el-button type="primary" @click="handleSubmit">提交</el-button>
+      </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>
+
+    <el-dialog
+      v-model="auditDialogVisible"
+      title="审核"
+      width="560px"
+      :close-on-click-modal="false"
+    >
+      <el-form :model="auditForm" label-width="90px">
+        <el-form-item label="审核结果">
+          <el-radio-group v-model="auditForm.authorizedStatus">
+            <el-radio label="1">通过</el-radio>
+            <el-radio label="2">驳回</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="审核意见">
+          <el-input v-model="auditForm.reviewFeedback" type="textarea" :rows="4" placeholder="请输入审核意见" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="auditDialogVisible = false">取消</el-button>
+        <el-button type="primary" :loading="auditSubmitLoading" @click="handleAuditSubmit">确定</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 auditDialogVisible = ref(false);
+const auditSubmitLoading = ref(false);
+const auditForm = ref({
+  authorizedStatus: '1',
+  reviewFeedback: ''
+});
+
+// 判断是新增还是编辑模式
+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 isAuditMode = () => {
+  return String(route.query.action || '') === 'audit';
+};
+
+const openAuditDialog = () => {
+  auditForm.value = {
+    authorizedStatus: '1',
+    reviewFeedback: ''
+  };
+  auditDialogVisible.value = true;
+};
+
+const handleAuditSubmit = async () => {
+  if (!editId.value) {
+    ElMessage.error('缺少ID');
+    return;
+  }
+  try {
+    auditSubmitLoading.value = true;
+    await updateSupplierauthorize({
+      id: editId.value,
+      authorizedStatus: auditForm.value.authorizedStatus,
+      reviewFeedback: auditForm.value.reviewFeedback
+    } as any);
+    ElMessage.success('审核成功');
+    auditDialogVisible.value = false;
+    router.back();
+  } catch (e) {
+    console.error('审核失败:', e);
+    ElMessage.error('审核失败');
+  } finally {
+    auditSubmitLoading.value = false;
+  }
+};
+
+/** 加载详情数据(编辑模式) */
+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;
+      }
+    }
+    
+    // 收集所有分类数据
+    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 = {
+      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() // 详情数据也并行加载
+    ]);
+
+    if (isAuditMode()) {
+      openAuditDialog();
+    }
+  } 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>

+ 686 - 0
src/views/supplier/supplierexam/index.vue

@@ -0,0 +1,686 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索表单 -->
+    <el-form :model="searchParams" :inline="true" class="search-form" >
+      
+      <el-form-item label="品牌名称">
+        <el-select
+          v-model="searchParams.brandName"
+          placeholder="请选择品牌"
+          clearable
+          filterable
+          remote
+          :remote-method="searchBrand"
+          :loading="brandLoading"
+          style="width: 200px;"
+          @visible-change="handleBrandDropdownVisible"
+        >
+          <el-option
+            v-for="brand in brandList"
+            :key="brand.id"
+            :label="brand.brandName"
+            :value="brand.brandName"
+          />
+          <el-option v-if="brandLoading" disabled value="">
+            <div style="text-align: center;">加载中...</div>
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="品牌编号">
+        <el-input v-model="searchParams.brandNo" placeholder="请输入品牌编号" clearable style="width: 200px;" />
+      </el-form-item>
+      <el-form-item label="省">
+        <el-select
+          v-model="searchParams.province"
+          placeholder="请选择省"
+          clearable
+          filterable
+          style="width: 200px;"
+          @change="handleProvinceChange"
+          @clear="handleProvinceClear"
+        >
+          <el-option
+            v-for="p in provinceOptions"
+            :key="p.value"
+            :label="p.label"
+            :value="p.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="市">
+        <el-select
+          v-model="searchParams.city"
+          placeholder="请选择市"
+          clearable
+          filterable
+          :disabled="!searchParams.province"
+          style="width: 200px;"
+        >
+          <el-option
+            v-for="c in cityOptions"
+            :key="c.value"
+            :label="c.label"
+            :value="c.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
+        <el-button icon="Refresh" @click="handleReset">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 产品线管理列表以及分页卡片 -->
+    <el-card shadow="never" class="table-card">
+      <template #header>
+        <div class="table-header-content">
+          <span class="table-title">品牌授权信息列表</span>
+          
+        </div>
+      </template>
+
+      <!-- 授权详情信息列表 -->
+      <el-table v-loading="loading" :data="authorizationList" border style="width: 100%">
+        <el-table-column prop="supplierName" label="供应商名称" align="center" />
+        <el-table-column prop="brandName" label="品牌名称" align="center" />
+        <el-table-column label="一级类目" align="center">
+          <template #default="scope">
+            <span>{{ scope.row.categorysMap?.oneLevelName || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="二级类目" align="center">
+          <template #default="scope">
+            <span>{{ scope.row.categorysMap?.twoLevelName || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="三级类目" align="center">
+          <template #default="scope">
+            <span>{{ scope.row.categorysMap?.threeLevelName || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="authorizationEndTime" label="资质到期日期" align="center">
+          <template #default="scope">
+            <span>{{ scope.row.authorizationEndTime ? formatDate(scope.row.authorizationEndTime) : '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="授权区域(省)" align="center">
+          <template #default="scope">
+            <el-tooltip
+              :content="formatAuthorizedProvinces(scope.row)"
+              placement="top"
+              :disabled="formatAuthorizedProvinces(scope.row) === '-'"
+            >
+              <span class="cell-ellipsis">{{ formatAuthorizedProvinces(scope.row) }}</span>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column label="授权区域(市)" align="center">
+          <template #default="scope">
+            <el-tooltip
+              :content="formatAuthorizedCities(scope.row)"
+              placement="top"
+              :disabled="formatAuthorizedCities(scope.row) === '-'"
+            >
+              <span class="cell-ellipsis">{{ formatAuthorizedCities(scope.row) }}</span>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column prop="authorizedStatus" label="状态" align="center">
+          <template #default="scope">
+            <span>{{ getAuthorizedStatusText(scope.row.authorizedStatus) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="180">
+          <template #default="scope">
+            <div class="flex items-center justify-center gap-1 whitespace-nowrap">
+              <el-button link type="primary" @click="handleView(scope.row)">查看</el-button>
+              <el-button link type="primary" @click="handleAudit(scope.row)">审核</el-button>
+              <el-button link type="primary" @click="handleEdit(scope.row)">编辑</el-button>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页 -->
+      <div class="pagination-container">
+        <el-pagination
+          v-model:current-page="pagination.pageNum"
+          v-model:page-size="pagination.pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="pagination.total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+
+    <el-dialog
+      v-model="auditDialogVisible"
+      title="审核"
+      width="560px"
+      :close-on-click-modal="false"
+    >
+      <el-form :model="auditForm" label-width="90px">
+        <el-form-item label="审核结果">
+          <el-select v-model="auditForm.authorizedStatus" placeholder="请选择" style="width: 100%;">
+            <el-option v-for="item in authorizedStatusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="审核意见">
+          <el-input v-model="auditForm.reviewFeedback" type="textarea" :rows="4" placeholder="请输入审核意见" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="auditDialogVisible = false">取消</el-button>
+        <el-button type="primary" :loading="auditSubmitLoading" @click="handleAuditSubmit">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, nextTick, computed, getCurrentInstance, toRefs } from 'vue';
+import { useRouter, useRoute } from 'vue-router';
+import { useUserStore } from '@/store/modules/user';
+import { getAuthorizeDetailList, examSupplierauthorize } from '@/api/supplier/supplierauthorize';
+import { listBrand } from '@/api/product/brand';
+import { ElMessage } from 'element-plus';
+
+defineOptions({
+  name: 'Author2015618489107828737'
+});
+
+const router = useRouter();
+const route = useRoute();
+
+const editPath = '/supplierexam/edit';
+const detailPath = '/supplierexam/detail';
+
+const { proxy } = getCurrentInstance() as any;
+const { authorized_status } = toRefs<any>(proxy?.useDict('authorized_status'));
+
+const authorizedStatusOptions = computed(() => {
+  return (authorized_status.value || []).filter((d: any) => String(d?.value) !== '0');
+});
+
+const auditDialogVisible = ref(false);
+const auditSubmitLoading = ref(false);
+const auditId = ref<string | number>('');
+const auditForm = ref({
+  authorizedStatus: '1',
+  reviewFeedback: ''
+});
+
+const userStore = useUserStore();
+const authorizationList = ref<any[]>([]);
+const loading = ref(false);
+
+const supplierNo = computed(() => {
+  const q = route.query as Record<string, any>;
+  return q.supplierNo || q.no || (userStore as any).supplierNo;
+});
+
+// 授权区域(省/市)回显:使用 element-china-area-data
+const areaOptions = ref<any[]>([]);
+const provinceOptions = ref<any[]>([]);
+const cityOptions = ref<any[]>([]);
+
+// 品牌相关
+const brandList = ref<any[]>([]);
+const brandLoading = ref(false);
+const brandPagination = ref({
+  pageNum: 1,
+  pageSize: 100
+});
+const hasMoreBrands = ref(true);
+const isSearchMode = ref(false); // 是否在搜索模式
+
+// 搜索参数
+const searchParams = ref({
+  brandNo: '',
+  brandName: '',
+  province: '', // 省ID(2位)
+  city: ''      // 市ID(4位)
+});
+
+// 分页参数
+const pagination = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0
+});
+
+/** 获取品牌列表 */
+const getBrandList = async (reset = false) => {
+  if (reset) {
+    brandPagination.value.pageNum = 1;
+    brandList.value = [];
+  }
+
+  try {
+    brandLoading.value = true;
+    const res = await listBrand({
+      pageNum: brandPagination.value.pageNum,
+      pageSize: brandPagination.value.pageSize
+    });
+    
+    const newBrands = res.rows || [];
+    if (reset) {
+      brandList.value = newBrands;
+    } else {
+      brandList.value = [...brandList.value, ...newBrands];
+    }
+    
+    // 判断是否还有更多数据
+    hasMoreBrands.value = newBrands.length === brandPagination.value.pageSize;
+    
+    console.log('品牌列表:', brandList.value);
+  } catch (e) {
+    console.error('获取品牌列表失败:', e);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 搜索品牌 */
+const searchBrand = async (query: string) => {
+  if (!query) {
+    isSearchMode.value = false;
+    await getBrandList(true);
+    return;
+  }
+  
+  isSearchMode.value = true;
+  try {
+    brandLoading.value = true;
+    const res = await listBrand({
+      brandName: query,
+      pageNum: 1,
+      pageSize: 100
+    });
+    brandList.value = res.rows || [];
+    hasMoreBrands.value = false; // 搜索模式下不支持加载更多
+  } catch (e) {
+    console.error('搜索品牌失败:', e);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 下拉框显示/隐藏 */
+const handleBrandDropdownVisible = async (visible: boolean) => {
+  if (visible && brandList.value.length === 0) {
+    await getBrandList(true);
+    // 添加滚动监听
+    await nextTick();
+    addScrollListener();
+  } else if (!visible) {
+    // 移除滚动监听
+    removeScrollListener();
+  }
+};
+
+/** 添加滚动监听 */
+const addScrollListener = () => {
+  const dropdown = document.querySelector('.el-select-dropdown__wrap');
+  if (dropdown) {
+    dropdown.addEventListener('scroll', handleScroll);
+  }
+};
+
+/** 移除滚动监听 */
+const removeScrollListener = () => {
+  const dropdown = document.querySelector('.el-select-dropdown__wrap');
+  if (dropdown) {
+    dropdown.removeEventListener('scroll', handleScroll);
+  }
+};
+
+/** 处理滚动事件 */
+const handleScroll = async (e: Event) => {
+  const target = e.target as HTMLElement;
+  const scrollTop = target.scrollTop;
+  const scrollHeight = target.scrollHeight;
+  const clientHeight = target.clientHeight;
+  
+  // 滚动到底部,且不在搜索模式,且还有更多数据,且不在加载中
+  if (scrollTop + clientHeight >= scrollHeight - 10 && 
+      !isSearchMode.value && 
+      hasMoreBrands.value && 
+      !brandLoading.value) {
+    await loadMoreBrands();
+  }
+};
+
+/** 加载更多品牌 */
+const loadMoreBrands = async () => {
+  brandPagination.value.pageNum++;
+  await getBrandList(false);
+};
+
+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
+    };
+  });
+};
+
+/** 根据value查找区域名称 */
+const findRegionNameById = (id: string | number, regions: any[]): string => {
+  const targetId = String(id ?? '').trim();
+  if (!targetId) return '';
+  const region = (regions || []).find((r: any) => String(r.value) === targetId);
+  return region?.label || '';
+};
+
+const isProvinceCode = (val: any) => {
+  const s = String(val ?? '').trim();
+  return /^\d{2}$/.test(s);
+};
+
+const isCityCode = (val: any) => {
+  const s = String(val ?? '').trim();
+  return /^\d{4}$/.test(s);
+};
+
+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;
+};
+
+/** 从行数据中提取授权区域ID列表(兼容 authorizedArea / province / city) */
+const getRowAreaIds = (row: any): string[] => {
+  if (row?.authorizedArea) {
+    return String(row.authorizedArea)
+      .split(',')
+      .map((s) => String(s ?? '').trim())
+      .filter(Boolean);
+  }
+
+  const ids: string[] = [];
+  const p = String(row?.province ?? '').trim();
+  const c = String(row?.city ?? '').trim();
+  if (p) ids.push(p);
+  if (c) ids.push(c);
+  return ids;
+};
+
+/** 授权区域(省)回显 */
+const formatAuthorizedProvinces = (row: any) => {
+  const ids = getRowAreaIds(row);
+  const provinceIds = ids.filter((id) => isProvinceCode(id));
+  const provinceNames = provinceIds
+    .map((pid) => findRegionNameById(pid, areaOptions.value))
+    .filter(Boolean);
+  return provinceNames.length ? Array.from(new Set(provinceNames)).join(',') : '-';
+};
+
+/** 授权区域(市)回显 */
+const formatAuthorizedCities = (row: any) => {
+  const ids = getRowAreaIds(row);
+  const cityIds = ids.filter((id) => isCityCode(id));
+  if (!cityIds.length) return '-';
+
+  const provinceMap = new Map<string, Set<string>>();
+  cityIds.forEach((cid) => {
+    const provinceId = String(cid).slice(0, 2);
+    const provinceName = findRegionNameById(provinceId, areaOptions.value);
+    if (!provinceName) return;
+
+    const province = areaOptions.value.find((p: any) => String(p.value) === String(provinceId));
+    const cityName = province ? findRegionNameById(cid, province.children || []) : '';
+    const displayCityName = normalizeCityDisplayName(provinceName, cityName);
+    if (!displayCityName) return;
+
+    if (!provinceMap.has(provinceName)) {
+      provinceMap.set(provinceName, new Set());
+    }
+    provinceMap.get(provinceName)!.add(displayCityName);
+  });
+
+  const allCities: string[] = [];
+  provinceMap.forEach((cities) => {
+    allCities.push(...Array.from(cities));
+  });
+  return allCities.length ? allCities.join(',') : '-';
+};
+
+/** 初始化授权区域选项数据 */
+const initAreaOptions = async () => {
+  try {
+    const mod: any = await import('element-china-area-data');
+    areaOptions.value = toProvinceCityOptions(mod?.regionData as any);
+    provinceOptions.value = areaOptions.value || [];
+  } catch (e) {
+    console.error('获取授权区域数据失败:', e);
+  }
+};
+
+const refreshCityOptions = () => {
+  const pid = String(searchParams.value.province ?? '').trim();
+  if (!pid) {
+    cityOptions.value = [];
+    return;
+  }
+  const province = provinceOptions.value.find((p: any) => String(p.value) === pid);
+  cityOptions.value = province?.children || [];
+};
+
+const handleProvinceChange = () => {
+  searchParams.value.city = '';
+  refreshCityOptions();
+};
+
+const handleProvinceClear = () => {
+  searchParams.value.city = '';
+  refreshCityOptions();
+};
+
+/** 获取授权详情列表 */
+const getAuthorizationList = async () => {
+  if (!supplierNo.value) {
+    console.warn('supplierNo 为空,授权详情将按当前条件尝试查询');
+  }
+
+  try {
+    loading.value = true;
+    console.log('获取授权详情列表,供应商编号:', supplierNo.value);
+    const res = await getAuthorizeDetailList({ 
+      supplierNo: supplierNo.value,
+      brandNo: searchParams.value.brandNo,
+      brandName: searchParams.value.brandName,
+      province: searchParams.value.province,
+      city: searchParams.value.city,
+      pageNum: pagination.value.pageNum,
+      pageSize: pagination.value.pageSize
+    });
+    authorizationList.value = res.rows || [];
+    pagination.value.total = res.total || 0;
+    console.log('授权详情列表:', authorizationList.value);
+  } catch (e) {
+    console.error('获取授权详情列表失败:', e);
+    ElMessage.error('获取授权详情列表失败');
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 搜索 */
+const handleSearch = () => {
+  pagination.value.pageNum = 1;
+  getAuthorizationList();
+};
+
+/** 重置 */
+const handleReset = () => {
+  searchParams.value = {
+    brandNo: '',
+    brandName: '',
+    province: '',
+    city: ''
+  };
+  refreshCityOptions();
+  pagination.value.pageNum = 1;
+  getAuthorizationList();
+};
+
+/** 添加授权 */
+const handleAdd = () => {
+  router.push({ path: editPath });
+};
+
+/** 查看 */
+const handleView = (row: any) => {
+  router.push({ path: detailPath, query: { id: row.id } });
+};
+
+/** 审核 */
+const handleAudit = (row: any) => {
+  auditId.value = row?.id;
+  auditForm.value = {
+    authorizedStatus: '1',
+    reviewFeedback: ''
+  };
+  auditDialogVisible.value = true;
+};
+
+const handleAuditSubmit = async () => {
+  if (!auditId.value) {
+    ElMessage.error('缺少ID');
+    return;
+  }
+  try {
+    auditSubmitLoading.value = true;
+    await examSupplierauthorize({
+      id: auditId.value,
+      authorizedStatus: auditForm.value.authorizedStatus,
+      reviewFeedback: auditForm.value.reviewFeedback
+    } as any);
+    ElMessage.success('审核成功');
+    auditDialogVisible.value = false;
+    await getAuthorizationList();
+  } catch (e) {
+    console.error('审核失败:', e);
+    ElMessage.error('审核失败');
+  } finally {
+    auditSubmitLoading.value = false;
+  }
+};
+
+/** 编辑 */
+const handleEdit = (row: any) => {
+  router.push({ path: editPath, query: { id: row.id, action: 'edit' } });
+};
+
+/** 分页大小改变 */
+const handleSizeChange = (size: number) => {
+  pagination.value.pageSize = size;
+  getAuthorizationList();
+};
+
+/** 当前页改变 */
+const handleCurrentChange = (page: number) => {
+  pagination.value.pageNum = page;
+  getAuthorizationList();
+};
+
+/** 格式化日期 */
+const formatDate = (date: string | Date) => {
+  if (!date) return '-';
+  const d = new Date(date);
+  // 使用本地时区格式化日期,避免时区问题
+  const year = d.getFullYear();
+  const month = String(d.getMonth() + 1).padStart(2, '0');
+  const day = String(d.getDate()).padStart(2, '0');
+  return `${year}-${month}-${day}`;
+};
+
+/** 获取授权状态文本 */
+const getAuthorizedStatusText = (status: string) => {
+  const target = String(status ?? '');
+  const matched = (authorized_status.value || []).find((d: any) => String(d?.value) === target);
+  return matched?.label || '未知';
+};
+
+onMounted(async () => {
+  // 并行加载品牌列表和授权详情列表
+  await Promise.all([
+    getBrandList(true),
+    initAreaOptions(),
+    getAuthorizationList()
+  ]);
+});
+</script>
+
+<style scoped>
+.app-container {
+  padding: 20px;
+  background: #f0f2f5;
+  min-height: calc(100vh - 84px);
+}
+
+.search-form {
+  background: #fff;
+  padding: 20px;
+  margin-bottom: 20px;
+  border-radius: 4px;
+}
+
+.table-card {
+  margin-top: 0px;
+}
+
+.table-header-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.table-title {
+  font-size: 16px;
+  font-weight: 500;
+  color: #333;
+}
+
+.empty-state {
+  text-align: center;
+  padding: 40px;
+  color: #999;
+}
+
+.pagination-container {
+  display: flex;
+  justify-content: flex-end;
+  padding-top: 20px;
+}
+
+.cell-ellipsis {
+  display: block;
+  width: 100%;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+</style>