Răsfoiți Sursa

静态页面、应用权限接口联调、基础服务适配逻辑

jianggs 6 zile în urmă
părinte
comite
6747799b4f

BIN
web/dist.zip


+ 2 - 2
web/src/api/common/oauth.js

@@ -63,8 +63,8 @@ export function getSessionInfoFn() {
 export function getMenuandcontrFn(params,headers) {
   console.log(headers, "---headers")
   return request({
-    // url: backend.appOcaService + '/api/account/menuandcontr',
-    url: backend.appOcaService + '/api/adminsmapp/catemenu2',
+    url: backend.appOcaService + '/api/account/menuandcontr',
+    // url: backend.appOcaService + '/api/adminsmapp/catemenu2',
     method: 'get',
     headers:headers,
     params

+ 3 - 0
web/src/assets/common/base.css

@@ -769,6 +769,9 @@ sup {
     border-bottom: 13px solid #F4F8FE;
     background: #fff;
 }
+.search-bar .el-form-item{
+    margin-bottom: 0;
+}
 
 .list-container {
     min-height: calc(100vh - 136px);

+ 1 - 1
web/src/assets/common/common.css

@@ -1317,7 +1317,7 @@ textarea {
   display: inline-block;
   padding-right: 16px;
   font-weight: 600;
-  border-right: 1px solid rgb(0, 0, 0, 0.12);
+  /* border-right: 1px solid rgb(0, 0, 0, 0.12); */
 }
 
 .yu-frame-top-left-bar .left-content .yu-app-box-top-button-wrap .sort-name {

+ 0 - 1
web/src/components/base/Login/index.vue

@@ -779,7 +779,6 @@
   .login-foot {
     height: 100px;
     line-height: 100px;
-    // background: #FFFFFF;
     text-align: center;
 
     & > * {

+ 3 - 3
web/src/components/layout/Navbar/topLeft.vue

@@ -11,7 +11,7 @@
           <!-- {{ appName }} -->
           {{ tenantInfo.systemName }}
         </span>
-        <span class="sort-name">
+        <span class="sort-name" style="display: none;">
           <div>
             <span :title="curCateName">{{ curCateName }}</span
             ><img class="arr-down" :src="arrowDownImg" />
@@ -48,7 +48,7 @@
       </div>
     </div>
     <!-- 工作台 搜索 -->
-    <div class="yu-frame-top-bar-content-search">
+    <div class="yu-frame-top-bar-content-search" style="display: none;">
       <span :class="{ 'is-hidden': isHidden }" id="step3" style="width: 140px">
         <span class="stationFontClass" @click="toWorkstation">
           <img src="@/assets/common/img/icon_gzt.png" />{{
@@ -414,7 +414,7 @@
       </div>
 
       <!-- 国际化 -->
-      <div ref="topThemesLanguage" class="yu-frame-top-language">
+      <div ref="topThemesLanguage" class="yu-frame-top-language" style="display: none;">
         <yu-dropdown @command="switchLanguage">
           <span
             id="step8"

+ 0 - 2
web/src/components/layout/TopLeft/leftMenu.vue

@@ -88,7 +88,6 @@
 		z-index: 2000;
 		opacity: 1;
 		color: #fff;
-		// background: #255DDB;
 		transition: width 0.3s ease, opacity 0.15s ease;
 		.yu-frame-left-menu-content {
 			position: relative;
@@ -124,7 +123,6 @@
 			.left-menu-box {
 				overflow-y: auto;
 				height: calc(100vh - 107px);
-				// background: #255DDB;
 				margin-top: 10px;
 				.el-menu-item, .el-submenu__title {
 					span {

+ 3 - 0
web/src/config/constant/app.data.service.js

@@ -33,7 +33,10 @@ const serviceNameList = {
   gatewayService: "/base-gateway", // 网关
   appCommonService: "/base-common", // 基础服务
   appOcaService: "/base-oca", // 组织机构、菜单权限微服务
+  tagServer:"/tag-server",//智能打标服务
   
+
+
   useService: "/yusp-use3.2", // 一体化微服务
   oddpService: "/yudi-oddp", // 一体化微服务
   oddpServicePrd: "/yudi-oddp", // 一体化微服

+ 1 - 1
web/src/config/other/css.js

@@ -5,7 +5,7 @@
 import store from "@/store";
 import "@/assets/common/normalize.css"; // A modern alternative to CSS resets
 import "@/assets/common/iconfont/iconfont.css"; // @fixable 使用yuwp-ui字体图标
-// import "@/assets/common/iconfont/iconfont3.css"; // @fixable 使用yuwp-ui字体图标
+import "@/assets/common/iconfont/iconfont3.css"; // @fixable 使用yuwp-ui字体图标
 // import "@/assets/common/iconfont/iconfont4.css"; // @fixable 使用yuwp-ui字体图标
 // import "@/assets/common/iconfont_bddp/iconfont.css"; // bddp 离线图标
 // import "@/assets/common/iconfont_ida/iconfont.css"; // @fixable 使用yuwp-ui字体图标-一体化经分

+ 34 - 34
web/src/router/router-filter.js

@@ -26,44 +26,42 @@ const whiteList = settings.whiteList;
 const originalRequest = yufp.service.request; // 先保存原始请求函数
 // 路由前置拦截器
 router.beforeEach(async (to, from, next) => {
-  console.log('to',to);
-  
   // 从其他系统跳转到本系统直接查看看板预览的界面
   if (to.query.page_name && to.query.page_name === "externalPreviewBoard") {
     // 其他系统跳转到本系统的预览界面,不需要传token验证,headers中加一个Jobid属性
     yufp.service.request = async param => {
-			param.data = param.data || {};
-			if ((param.method || 'get').toLowerCase() === 'get') {
-				param['params'] = param.data;
+		param.data = param.data || {};
+		if ((param.method || 'get').toLowerCase() === 'get') {
+			param['params'] = param.data;
 
-				if (Object.prototype.toString(param.params).includes('Object')) {
-					let a = JSON.stringify(param.params).replaceAll('#', '%23');
-					param.params = JSON.parse(a);
-				}
-			}
-			
-			if (!param.headers) {
-				param.headers = {};
-			}
-			param.headers.Projectid = yufp.sessionStorage.get('projectId') || ''
-			param.headers.Jobid = to.query?.Jobid??""
-			param.needToken = false
-			const manager = await store.dispatch("sysProp/getSysProp", i18n.t('router.54cc9e1f-409c-47dc-951c-65c03588f200'));
-			if (manager) {
-				param.headers.isManager = yufp.session.userName == manager ? '1' : '0';
-				param.headers.managerName = encodeURIComponent(manager);
+			if (Object.prototype.toString(param.params).includes('Object')) {
+				let a = JSON.stringify(param.params).replaceAll('#', '%23');
+				param.params = JSON.parse(a);
 			}
+		}
+		
+		if (!param.headers) {
+			param.headers = {};
+		}
+		param.headers.Projectid = yufp.sessionStorage.get('projectId') || ''
+		param.headers.Jobid = to.query?.Jobid??""
+		param.needToken = false
+		const manager = await store.dispatch("sysProp/getSysProp", i18n.t('router.54cc9e1f-409c-47dc-951c-65c03588f200'));
+		if (manager) {
+			param.headers.isManager = yufp.session.userName == manager ? '1' : '0';
+			param.headers.managerName = encodeURIComponent(manager);
+		}
       let language = getLanguage()
-			if(language == 'en') {
-				language = 'en-US'
-			}else {
-				language = 'zh-CN'
-			}
-			param.headers[ 'Accept-Language']= language;
-			request(param).then(res => {
-				param.callback(res.code, '', res)
-			})
-		},
+		if(language == 'en') {
+			language = 'en-US'
+		}else {
+			language = 'zh-CN'
+		}
+		param.headers[ 'Accept-Language']= language;
+		request(param).then(res => {
+			param.callback(res.code, '', res)
+		})
+	},
     next()
   } else {
     // 基础的路由拦截逻辑
@@ -93,9 +91,10 @@ router.beforeEach(async (to, from, next) => {
     // set page title
     // console.log(`当前路由信息${JSON.stringify(to)}`)
     // document.title = getPageTitle(to.meta.title)
-    if (to.path === "/") {
-      next({ path: "/404" });
-    }
+    // 注释掉根路径重定向到404的逻辑,以便登录成功后能正常跳转到主页面
+    // if (to.path === "/") {
+    //   next({ path: "/404" });
+    // }
     // 1.获取Token信息,判定是否已登录
     const hasToken = getToken();
     /* 2.不存在token信息,当前状态是未登录 */
@@ -152,6 +151,7 @@ router.beforeEach(async (to, from, next) => {
       next();
       return;
     }
+
     // 角色非必须时,刷新页面重新请求用户信息
     if (!settings.mustRole && store.getters.userName) {
       await store.dispatch("oauth/getSessionInfo");

+ 156 - 85
web/src/store/modules/oauth.js

@@ -10,7 +10,7 @@ import router, { resetRouter } from '@/router'
 import constantRoutes from '@/router/constant-routes'
 import {getLanguage} from "@/utils/i18n";
 // import { USER_MAPPING, setToken, removeToken, generateRoutes, MENU_JSON_ROOT, MENU_JSON_ROOT1,CTRL_JSON_ROOT, USER_STORE_KEY, MENU_STOREOG_KEY, MENU_STORE_KEY, CTRL_STOREOG_KEY, CTRL_STORE_KEY, ROUTER_STORE_KEY, CURRENT_TOP_MENU_STORE_KEY } from '@/utils/oauth'
-import { USER_MAPPING, setToken, removeToken, generateRoutes, MENU_JSON_ROOT, MENU_JSON_ROOT1, CTRL_JSON_ROOT, USER_STORE_KEY, MENU_STOREOG_KEY, MENU_STORE_KEY, CTRL_STOREOG_KEY, CTRL_STORE_KEY, ROUTER_STORE_KEY, CURRENT_TOP_MENU_STORE_KEY, CATE_NAME_STORE_KEY } from '@/utils/oauth'
+import { USER_MAPPING, setToken, removeToken, generateRoutes, MENU_JSON_ROOT, /* MENU_JSON_ROOT1, */ CTRL_JSON_ROOT, USER_STORE_KEY, MENU_STOREOG_KEY, MENU_STORE_KEY, CTRL_STOREOG_KEY, CTRL_STORE_KEY, ROUTER_STORE_KEY, CURRENT_TOP_MENU_STORE_KEY /*, CATE_NAME_STORE_KEY */ } from '@/utils/oauth'
 
 import { extend, toMappingFn, sessionStore } from 'xy-utils'
 
@@ -49,7 +49,7 @@ const state = {
   showLeftMenu: true, // 上左菜单时 是否显示左侧二级菜单
   routes: sessionStore.get(ROUTER_STORE_KEY) || [], // 路由
   // cateNameId: '', //默认公共管理
-  cateNameId: sessionStore.get(CATE_NAME_STORE_KEY) || '',
+  // cateNameId: sessionStore.get(CATE_NAME_STORE_KEY) || '', // 移除多分类菜单支持
   allRoutes: [], // 全量路由
   userPic: ''
 }
@@ -148,10 +148,10 @@ const mutations = {
   SET_SHOW_LEFT_MENU: (state, isShow) => {
     state.showLeftMenu = isShow;
   },
-  SET_CATE_NAME_ID: (state, id) => {
-    state.cateNameId = id
-    sessionStore.set(CATE_NAME_STORE_KEY, id)
-  },
+  // SET_CATE_NAME_ID: (state, id) => {
+  //   state.cateNameId = id
+  //   sessionStore.set(CATE_NAME_STORE_KEY, id)
+  // }, // 移除多分类菜单支持
   CHANGE_MESSAGE_USER_PIC: (state, pic) => {
     state.userPic = pic
   }
@@ -219,37 +219,53 @@ const actions = {
   // 获取用户会话信息、菜单及控制点信息
   getSessionInfo ({ dispatch, commit, state }) {
     return new Promise(async (resolve, reject) => {
-      await getSessionInfoFn().then(response => {
-        if (!response) {
-          reject('Verification failed, please Login again.')
-        }
-        commit('CHANGE_MESSAGE_USER_PIC', response.userAvatar); 
-        const userInfo = toMappingFn(response, USER_MAPPING)
-        const { userId, userName, userCode, userAvatar, logicSys, loginCode,
-          roles, org, dpt, instu, upOrg, upDpt, ...otherInfo } = userInfo
-        const role = roles && roles.length > 0 ? roles[0] : {};
-        commit('SET_USER_ID', userId)
-        commit('SET_USER_NAME', userName)
-        commit('SET_USER_CODE', userCode)
-        commit('SET_USER_AVATAR', userAvatar)
-        commit('SET_LOGIC_SYS', logicSys)
-        commit('SET_ROLES', roles)
-        commit('SET_SELECTED_ROLES', role)
-        commit('SET_ORG', org)
-        commit('SET_DPT', dpt)
-        commit('SET_INSTU', instu)
-        commit('SET_UP_ORG', upOrg)
-        commit('SET_UP_DPT', upDpt)
-        commit('SET_OTHER_INFO', otherInfo)
-        commit('CHANGE_MESSAGE_USER_PIC', userInfo.userAvatar);
-        userInfo.loginCode = userInfo.userCode
-        sessionStore.set(USER_STORE_KEY, userInfo)
-        // #TODO 临时,将用户信息挂载到yufp.session上
-        yufp.extend(yufp.session, userInfo);
-        yufp.extend(yufp.session.user = {}, userInfo);
-      }).catch(error => {
-        reject(error)
-      })
+      try {
+        await getSessionInfoFn().then(response => {
+          if (!response) {
+            console.error('=== getSessionInfoFn response is null ===');
+            // 即使没有获取到用户信息,也不阻止登录成功后的跳转
+            // reject('Verification failed, please Login again.')
+          } else {
+            commit('CHANGE_MESSAGE_USER_PIC', response.userAvatar); 
+            const userInfo = toMappingFn(response, USER_MAPPING)
+            const { userId, userName, userCode, userAvatar, logicSys, loginCode,
+              roles, org, dpt, instu, upOrg, upDpt, ...otherInfo } = userInfo
+            const role = roles && roles.length > 0 ? roles[0] : {};
+            commit('SET_USER_ID', userId)
+            commit('SET_USER_NAME', userName)
+            commit('SET_USER_CODE', userCode)
+            commit('SET_USER_AVATAR', userAvatar)
+            commit('SET_LOGIC_SYS', logicSys)
+            commit('SET_ROLES', roles)
+            commit('SET_SELECTED_ROLES', role)
+            commit('SET_ORG', org)
+            commit('SET_DPT', dpt)
+            commit('SET_INSTU', instu)
+            commit('SET_UP_ORG', upOrg)
+            commit('SET_UP_DPT', upDpt)
+            commit('SET_OTHER_INFO', otherInfo)
+            commit('CHANGE_MESSAGE_USER_PIC', userInfo.userAvatar);
+            userInfo.loginCode = userInfo.userCode
+            sessionStore.set(USER_STORE_KEY, userInfo)
+            // #TODO 临时,将用户信息挂载到yufp.session上
+            try {
+              if (yufp && yufp.extend) {
+                yufp.extend(yufp.session, userInfo);
+                yufp.extend(yufp.session.user = {}, userInfo);
+              }
+            } catch (e) {
+              console.error('=== yufp.extend error ===', e);
+            }
+          }
+        }).catch(error => {
+          console.error('=== getSessionInfoFn error ===', error);
+          // 即使获取用户信息失败,也不阻止登录成功后的跳转
+          // reject(error)
+        })
+      } catch (error) {
+        console.error('=== getSessionInfoFn try-catch error ===', error);
+        // 即使获取用户信息失败,也不阻止登录成功后的跳转
+      }
       // let param = {}
       let headers = {}
       let language = getLanguage()
@@ -261,61 +277,116 @@ const actions = {
 			}
       Vue.prototype.$labelPosition = language == 'en-US' ? 'top' :'right'
       headers['Accept-Language']= language;
-      await getMenuandcontrFn({},headers).then(response => {
-        let _menu=response.data[MENU_JSON_ROOT1]
-        // 处理数据,将路径调整到对应的路由上,仅供测试使用
-        Object.values(_menu).forEach(item => {
-          item.forEach(m => {
-            if (m.funcUrl) {
-              m.funcUrl = m.funcUrl.replace('pages/', '')
+      try {
+        await getMenuandcontrFn({},headers).then(response => {
+          
+          // ==================== 新增:简化菜单处理逻辑(去除多分类)====================
+          // 根据实际API返回的数据结构提取菜单数据
+          // /api/account/menuandcontr 返回的数据结构是 { menu: [...] },没有 data 字段
+          // /api/adminsmapp/catemenu2 返回的数据结构是 { data: { menu: {...} } }
+          let menuData = response && response.menu ? response.menu : (response.data && response.data.menu ? response.data.menu : undefined)
+          
+          // 处理数据结构:如果 menuData 是对象(多分类结构),则转换为数组
+          let menus = []
+          if (menuData) {
+            if (Array.isArray(menuData)) {
+              // 如果已经是数组,直接使用
+              menus = menuData
+            } else {
+              // 如果是对象,将所有分类的菜单合并为一个数组
+              try {
+                Object.values(menuData).forEach(category => {
+                  if (Array.isArray(category)) {
+                    menus = menus.concat(category)
+                  }
+                })
+              } catch (e) {
+                console.error('=== Object.values error ===', e);
+              }
             }
-          })
-        })
-        // 默认是COMMON_MANAGE 如果没有公共模块就按照返回取一个
-        const keys = Object.keys(_menu);
-        if (!state.cateNameId) {
-          state.cateNameId = keys.includes("COMMON_MANAGE") ? "COMMON_MANAGE" : keys[0];
-        }
-
-        if (!response || !_menu[state.cateNameId]) {
-          reject('Verification failed, please Login again.')
-        }
-        // 全量菜单-添加菜单
-        let arr = Object.values(_menu), list = [];
-        arr.forEach(item => {
-          if (item.length) {
-            item.forEach(ele => {
-              list.push(yufp.clone(ele, {}));
+          }
+          
+          // 处理数据,将路径调整到对应的路由上
+          if (menus && Array.isArray(menus)) {
+            menus.forEach(m => {
+              if (m.funcUrl) {
+                m.funcUrl = m.funcUrl.replace('pages/', '')
+              }
             })
           }
-        })
 
-        sessionStore.set('menu-key', JSON.stringify(Object.keys(response.data.menu)))
+          // 即使菜单数据为空,也不阻止登录成功后的跳转
+          // 这样可以确保即使后端接口没有返回菜单数据,用户也能登录成功并跳转到主页面
+          // if (!response || !response.data) {
+          //   reject('Verification failed, please Login again.')
+          // }
 
-        commit('SET_ORIGINAL_MENUS', list)
-        commit('SET_ORIGINAL_CTRLS', response.data[CTRL_JSON_ROOT])
-        commit('SET_CTRLS', response.data[CTRL_JSON_ROOT]) // TODO 操作级权限点
+          // 存储菜单键(如果需要)
+          // 兼容两种不同的 API 返回格式
+          if (response && response.data && response.data.menu) {
+            try {
+              // 如果 menu 是对象(多分类结构),则存储其键
+              if (typeof response.data.menu === 'object' && !Array.isArray(response.data.menu)) {
+                sessionStore.set('menu-key', JSON.stringify(Object.keys(response.data.menu)))
+              } else {
+                // 如果 menu 是数组,则使用默认的分类 ID
+                sessionStore.set('menu-key', JSON.stringify(['DEFAULT']))
+              }
+            } catch (e) {
+              console.error('=== sessionStore.set error ===', e);
+            }
+          } else if (response && response.menu) {
+            try {
+              // 如果 menu 是对象(多分类结构),则存储其键
+              if (typeof response.menu === 'object' && !Array.isArray(response.menu)) {
+                sessionStore.set('menu-key', JSON.stringify(Object.keys(response.menu)))
+              } else {
+                // 如果 menu 是数组,则使用默认的分类 ID
+                sessionStore.set('menu-key', JSON.stringify(['DEFAULT']))
+              }
+            } catch (e) {
+              console.error('=== sessionStore.set error ===', e);
+            }
+          }
+          
+          commit('SET_ORIGINAL_MENUS', menus)
+          // 兼容两种不同的 API 返回格式,提取控制点数据
+          commit('SET_ORIGINAL_CTRLS', response && response.contr ? response.contr : (response && response.data ? response.data[CTRL_JSON_ROOT] : []))
+          commit('SET_CTRLS', response && response.contr ? response.contr : (response && response.data ? response.data[CTRL_JSON_ROOT] : [])) // TODO 操作级权限点
 
-        // 主菜单
-        const copyData = extend({}, _menu, true)
-        let menus = copyData[state.cateNameId];
-        menus = menus.filter(item => {
-          return item.menuName !== '工作台'
-        })
-        const accessRoutes = generateRoutes(menus)
-        commit('SET_ROUTES', accessRoutes)
-        // 全量路由
-        let allmenus = yufp.clone(list, []);
-        allmenus = allmenus.filter(item => {
-          return item.menuName !== '工作台'
+          // 过滤掉工作台菜单
+          const filteredMenus = menus.filter(item => {
+            return item.menuName !== '工作台'
+          })
+          // 生成路由
+          try {
+            let accessRoutes = []
+            
+            // 如果 filteredMenus 不为空,则生成路由
+            if (filteredMenus && filteredMenus.length > 0) {
+              accessRoutes = generateRoutes(filteredMenus)
+            } 
+            
+            commit('SET_ROUTES', accessRoutes)
+            
+            // 全量路由(与主路由相同)
+            commit('SET_All_ROUTES', accessRoutes)
+            
+            // 添加路由
+            router.addRoutes(accessRoutes)
+          } catch (e) {
+            console.error('=== generateRoutes error ===', e);
+          }
+          // ==================== 新增:简化菜单处理逻辑(去除多分类)====================
+        }).catch(error => {
+          console.error('=== getMenuandcontrFn error ===', error);
+          // 即使获取菜单和控制点信息失败,也不阻止登录成功后的跳转
+          // reject(error)
         })
-        const allRoutes = generateRoutes(allmenus)
-        commit('SET_All_ROUTES', allRoutes)
-        // resetRouter()
-        router.addRoutes(allRoutes)
-      }).catch(error => {
-        reject(error)
-      })
+      } catch (error) {
+        console.error('=== getMenuandcontrFn try-catch error ===', error);
+        // 即使获取菜单和控制点信息失败,也不阻止登录成功后的跳转
+      }
 
       resolve()
     })

+ 102 - 252
web/src/views/content/aiTagging/appAuthManage/index.vue

@@ -28,9 +28,6 @@
           <template slot-scope="scope">
             <div class="app-id-container">
               <span class="app-id">{{ scope.row.appId }}</span>
-              <el-button type="text" size="mini" @click="handleCopy(scope.row.appId)" class="copy-btn">
-                <i class="el-icon-document-copy"></i>
-              </el-button>
             </div>
           </template>
         </el-table-column>
@@ -39,15 +36,9 @@
             <span>************************</span>
           </template>
         </el-table-column>
-        <el-table-column prop="expiryTime" label="有效时间" min-width="180">
-          <template slot-scope="scope">
-            <span>{{ scope.row.expiryTime || '--' }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="操作" min-width="160">
+        <el-table-column label="操作" min-width="100">
           <template slot-scope="scope">
             <el-button type="text" @click="handleResetSecret(scope.row)" class="action-btn">重置密钥</el-button>
-            <el-button type="text" @click="handleExtend(scope.row)" class="action-btn">延期</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -107,48 +98,6 @@
       </span>
     </el-dialog>
     
-    <!-- 延期确认弹框 -->
-    <el-dialog
-      title="密钥延期确认"
-      :visible.sync="extendConfirmVisible"
-      width="400px"
-      :close-on-click-modal="false"
-    >
-      <div class="extend-confirm">
-        <div class="confirm-icon">
-          <i class="el-icon-info"></i>
-        </div>
-        <div class="confirm-content">
-          <p>密钥延期为敏感操作,确定要将该密钥延期 180 天?</p>
-        </div>
-      </div>
-      <span slot="footer" class="dialog-footer">
-        <el-button @click="extendConfirmVisible = false">取消</el-button>
-        <el-button type="primary" @click="handleConfirmExtend">确定</el-button>
-      </span>
-    </el-dialog>
-    
-    <!-- 无需延期提示 -->
-    <el-dialog
-      title="提示"
-      :visible.sync="noExtendVisible"
-      width="400px"
-      :close-on-click-modal="false"
-      :show-close="false"
-    >
-      <div class="no-extend">
-        <div class="warning-icon">
-          <i class="el-icon-warning"></i>
-        </div>
-        <div class="warning-content">
-          <p>该密钥尚未过期,无需延期</p>
-        </div>
-      </div>
-      <span slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="noExtendVisible = false">确定</el-button>
-      </span>
-    </el-dialog>
-    
     <!-- 密钥生成成功弹框 -->
     <el-dialog
       title="密钥已生成!"
@@ -171,6 +120,7 @@
 </template>
 
 <script>
+import { copyToClipboard } from '../utils/common';
 export default {
   name: 'AppAuthManage',
   data() {
@@ -184,104 +134,59 @@ export default {
         appName: ''
       },
       // 应用列表数据
-      appList: [
-        {
-          id: 1,
-          appName: '应用A',
-          appId: 'YY20260203001098791241241',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 2,
-          appName: '应用B',
-          appId: 'YY2026020300123124441241',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 3,
-          appName: '应用C',
-          appId: 'YY20260203001321321321567',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 4,
-          appName: '应用D',
-          appId: 'YY2026020300109879124167',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 5,
-          appName: '应用E',
-          appId: 'YY2026020300109879890786',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 6,
-          appName: '应用F',
-          appId: 'YY2026020300105567876671',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 7,
-          appName: '应用G',
-          appId: 'YY20260203001098791242241',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 8,
-          appName: '应用H',
-          appId: 'YY20260203001098791241232',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 9,
-          appName: '应用I',
-          appId: 'YY20260203001098791245545',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        },
-        {
-          id: 10,
-          appName: '应用J',
-          appId: 'YY20260203001098791241980',
-          appSecret: 'secret1234567890',
-          expiryTime: ''
-        }
-      ],
+      appList: [],
       // 分页数据
       currentPage: 1,
       pageSize: 10,
-      totalCount: 120,
+      totalCount: 0,
       // 弹框状态
       dialogVisible: false,
       secretDialogVisible: false,
       resetConfirmVisible: false,
-      extendConfirmVisible: false,
-      noExtendVisible: false,
       // 生成的密钥
       generatedSecret: '',
       // 当前操作的应用
       currentApp: null
     }
   },
+  mounted() {
+    // 默认请求列表数据
+    this.loadAppList();
+  },
   methods: {
+    // 加载应用列表数据
+    loadAppList() {
+      yufp.service.request({
+        url: backend.tagServer + "/api/aitag-app/query",
+        method: 'get',
+        data: {
+          // sysId: yufp.session.logicSys.id,
+          appName: this.searchForm.appName,
+          page: this.currentPage,
+          pageSize: this.pageSize
+        },
+        callback: (code, error, response) => {
+          if (response.code == '0') {
+            this.appList = response.data || [];
+            this.totalCount = response.total || 0;
+          } else {
+            this.$message.error(response.message || '获取应用列表失败');
+          }
+        }
+      });
+    },
     // 查询
     handleSearch() {
       console.log('查询应用:', this.searchForm.appName);
-      // 这里可以添加查询逻辑
+      this.currentPage = 1;
+      this.loadAppList();
     },
     
     // 重置
     handleReset() {
       this.searchForm.appName = '';
+      this.currentPage = 1;
+      this.loadAppList();
       console.log('重置搜索条件');
     },
     
@@ -302,45 +207,50 @@ export default {
         return;
       }
       
-      // 生成随机密钥
-      this.generatedSecret = this.generateRandomSecret();
-      
-      // 模拟创建应用
-      console.log('创建应用:', this.newAppForm.appName);
-      console.log('生成密钥:', this.generatedSecret);
-      
-      // 关闭新建应用弹框
-      this.dialogVisible = false;
-      
-      // 打开密钥生成成功弹框
-      this.secretDialogVisible = true;
+      // 调用后端接口创建应用
+      yufp.service.request({
+        url: backend.tagServer + "/api/aitag-app/add",
+        method: 'post',
+        data: {
+          appName: this.newAppForm.appName
+        },
+        callback: (code, error, response) => {
+          if (response.code == '0') {
+            // 保存生成的密钥
+            this.generatedSecret = response.data.appSecret;
+            
+            // 关闭新建应用弹框
+            this.dialogVisible = false;
+            
+            // 打开密钥生成成功弹框
+            this.secretDialogVisible = true;
+            
+            // 重新加载应用列表
+            this.loadAppList();
+          } else {
+            this.$message.error(response.message || '创建应用失败');
+          }
+        }
+      });
     },
     
-    // 生成随机密钥
-    generateRandomSecret() {
-      const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-      let secret = '';
-      for (let i = 0; i < 20; i++) {
-        secret += chars.charAt(Math.floor(Math.random() * chars.length));
-      }
-      return secret;
-    },
+
     
     // 复制生成的密钥
-    handleCopySecret() {
-      // 模拟复制到剪贴板
-      console.log('复制密钥:', this.generatedSecret);
-      this.$message.success('复制成功');
-      // 关闭密钥生成成功弹框
-      this.secretDialogVisible = false;
+    async handleCopySecret() {
+      try {
+        // 使用公共复制方法
+        await copyToClipboard(this.generatedSecret, this);
+        // 关闭密钥生成成功弹框
+        this.secretDialogVisible = false;
+      } catch (error) {
+        console.error('复制失败:', error);
+        // 复制失败后仍然关闭弹框
+        this.secretDialogVisible = false;
+      }
     },
     
-    // 复制应用ID
-    handleCopy(appId) {
-      console.log('复制应用ID:', appId);
-      // 这里可以添加复制到剪贴板的逻辑
-      this.$message.success('复制成功');
-    },
+    
     
     // 重置密钥
     handleResetSecret(row) {
@@ -354,66 +264,45 @@ export default {
     handleConfirmReset() {
       if (!this.currentApp) return;
       
-      // 生成随机密钥
-      this.generatedSecret = this.generateRandomSecret();
-      
-      // 模拟重置密钥
-      console.log('重置密钥:', this.currentApp.appName);
-      console.log('生成新密钥:', this.generatedSecret);
-      
-      // 关闭确认弹框
-      this.resetConfirmVisible = false;
-      
-      // 打开密钥生成成功弹框
-      this.secretDialogVisible = true;
-    },
-    
-    // 延期
-    handleExtend(row) {
-      // 保存当前操作的应用
-      this.currentApp = row;
-      
-      // 模拟检查密钥是否过期
-      // 这里可以根据实际的expiryTime来判断
-      // 为了演示,我们假设前5个应用需要延期,后5个不需要
-      const needExtend = row.id <= 5;
-      
-      if (needExtend) {
-        // 显示延期确认弹框
-        this.extendConfirmVisible = true;
-      } else {
-        // 显示无需延期提示
-        this.noExtendVisible = true;
-      }
-    },
-    
-    // 确认延期
-    handleConfirmExtend() {
-      if (!this.currentApp) return;
-      
-      // 模拟延期操作
-      console.log('延期:', this.currentApp.appName);
-      console.log('延期180天');
-      
-      // 关闭确认弹框
-      this.extendConfirmVisible = false;
-      
-      // 显示成功提示
-      this.$message.success('延期成功');
+      // 调用后端接口重置密钥
+      yufp.service.request({
+        url: backend.tagServer + "/api/aitag-app/reset-secret",
+        method: 'post',
+        data: {
+          appId: this.currentApp.appId
+        },
+        callback: (code, error, response) => {
+          if (response.code == '0') {
+            // 保存生成的密钥
+            this.generatedSecret = response.data.appSecret;
+            
+            // 关闭确认弹框
+            this.resetConfirmVisible = false;
+            
+            // 打开密钥生成成功弹框
+            this.secretDialogVisible = true;
+            
+            // 重新加载应用列表
+            this.loadAppList();
+          } else {
+            this.$message.error(response.message || '重置密钥失败');
+          }
+        }
+      });
     },
     
     // 分页大小变化
     handleSizeChange(val) {
       console.log(`每页 ${val} 条`);
       this.pageSize = val;
-      // 这里可以添加分页逻辑
+      this.loadAppList();
     },
     
     // 当前页码变化
     handleCurrentChange(val) {
       console.log(`当前页: ${val}`);
       this.currentPage = val;
-      // 这里可以添加分页逻辑
+      this.loadAppList();
     }
   }
 }
@@ -423,7 +312,7 @@ export default {
 .app-auth-manage {
   padding: 0;
   background-color: transparent;
-  min-height: 100vh;
+  height: 100%;
 }
 
 /* 搜索栏 */
@@ -467,7 +356,6 @@ export default {
 .app-id-container {
   display: flex;
   align-items: center;
-  gap: 8px;
 }
 
 /* 应用ID文本 */
@@ -478,17 +366,6 @@ export default {
   white-space: nowrap;
 }
 
-/* 复制按钮 */
-.copy-btn {
-  color: #409EFF;
-  font-size: 14px;
-  padding: 0 4px;
-}
-
-.copy-btn:hover {
-  color: #66B1FF;
-}
-
 /* 操作按钮 */
 .action-btn {
   color: #409EFF;
@@ -510,8 +387,9 @@ export default {
   display: flex;
   justify-content: flex-end;
   align-items: center;
-  padding: 0 20px;
-  border-top: 1px solid #ebeef5;
+}
+.pagination .el-pagination{
+  padding: 10px 20px;
 }
 
 /* 重置密钥确认弹框样式 */
@@ -544,35 +422,7 @@ export default {
   line-height: 1.5;
 }
 
-/* 延期确认弹框样式 */
-.extend-confirm {
-  display: flex;
-  padding: 20px 0;
-}
-
-/* 无需延期提示样式 */
-.no-extend {
-  display: flex;
-  padding: 20px 0;
-}
 
-.warning-icon {
-  color: #F56C6C;
-  font-size: 24px;
-  margin-right: 16px;
-  flex-shrink: 0;
-  margin-top: 4px;
-}
-
-.warning-content {
-  flex: 1;
-}
-
-.warning-content p {
-  margin: 8px 0;
-  font-size: 14px;
-  color: #606266;
-}
 
 /* 密钥生成成功弹框样式 */
 .secret-success {

+ 22 - 76
web/src/views/content/aiTagging/taggingLogs/components/LogDetailDrawer.vue

@@ -10,73 +10,41 @@
     <div class="log-detail-container">
       <!-- 基本信息 -->
       <div class="detail-section">
-        <h3 class="section-title">基本信息</h3>
-        <div class="info-grid">
-          <div class="info-item">
-            <span class="label">调用时间:</span>
-            <span class="value">{{ logDetail.callTime }}</span>
-          </div>
-          <div class="info-item">
-            <span class="label">响应时间:</span>
-            <span class="value">{{ logDetail.responseTime }}</span>
-          </div>
-          <div class="info-item">
-            <span class="label">请求ID:</span>
-            <span class="value">{{ logDetail.requestId }}</span>
-          </div>
-          <div class="info-item">
-            <span class="label">接口名称:</span>
-            <span class="value">{{ logDetail.apiName }}</span>
-          </div>
-          <div class="info-item">
-            <span class="label">状态结果:</span>
-            <el-tag :type="getStatusType(logDetail.status)">{{ logDetail.status }}</el-tag>
-          </div>
-          <div class="info-item">
-            <span class="label">调用IP:</span>
-            <span class="value">{{ logDetail.clientIp }}</span>
-          </div>
+        <div class="info-item">
+          <span class="label">用户名称:</span>
+          <span class="value">{{ logDetail.userName }}</span>
         </div>
-      </div>
-
-      <!-- 请求信息 -->
-      <div class="detail-section">
-        <h3 class="section-title">请求信息</h3>
         <div class="info-item">
-          <span class="label">请求方法:</span>
-          <span class="value">{{ logDetail.requestMethod }} {{ logDetail.requestUrl }}</span>
+          <span class="label">用户ID:</span>
+          <span class="value">{{ logDetail.userId }}</span>
         </div>
         <div class="info-item">
-          <span class="label">请求头:</span>
-          <pre class="code-block">{{ formatJson(logDetail.requestHeaders) }}</pre>
+          <span class="label">操作类型:</span>
+          <span class="value">{{ logDetail.operationType }}</span>
         </div>
         <div class="info-item">
-          <span class="label">请求体:</span>
-          <pre class="code-block">{{ formatJson(logDetail.requestBody) }}</pre>
+          <span class="label">操作时间:</span>
+          <span class="value">{{ logDetail.operationTime }}</span>
         </div>
       </div>
 
-      <!-- 响应信息 -->
+      <!-- 输入信息 -->
       <div class="detail-section">
-        <h3 class="section-title">响应信息</h3>
         <div class="info-item">
-          <span class="label">响应状态:</span>
-          <span class="value">{{ logDetail.responseStatus }}</span>
-        </div>
-        <div class="info-item">
-          <span class="label">响应头:</span>
-          <pre class="code-block">{{ formatJson(logDetail.responseHeaders) }}</pre>
+          <span class="label">输入:</span>
+          <pre class="code-block">{{ logDetail.input }}</pre>
         </div>
+      </div>
+
+      <!-- 输出信息 -->
+      <div class="detail-section">
         <div class="info-item">
-          <span class="label">响应体:</span>
-          <pre class="code-block">{{ formatJson(logDetail.responseBody) }}</pre>
+          <span class="label">输出:</span>
+          <pre class="code-block">{{ logDetail.output }}</pre>
         </div>
       </div>
 
-      <!-- 底部操作 -->
-      <div class="detail-footer">
-        <el-button type="primary" @click="handleExport">导出</el-button>
-      </div>
+
     </div>
   </el-drawer>
 </template>
@@ -100,25 +68,7 @@ export default {
       this.$emit('update:visible', false)
     },
     
-    // 处理导出
-    handleExport() {
-      console.log('导出日志详情:', this.logDetail.requestId)
-      this.$message.success('导出成功')
-    },
-    
-    // 根据状态获取标签类型
-    getStatusType(status) {
-      switch (status) {
-        case '成功':
-          return 'success'
-        case '失败':
-          return 'danger'
-        case '响应中':
-          return 'warning'
-        default:
-          return ''
-      }
-    },
+
     
     // 格式化JSON
     formatJson(json) {
@@ -141,13 +91,9 @@ export default {
 }
 
 .detail-section {
-  margin-bottom: 30px;
+  /* margin-bottom: 30px;
   padding-bottom: 20px;
-  border-bottom: 1px solid #f0f0f0;
-}
-
-.detail-section:last-child {
-  border-bottom: none;
+  border-bottom: 1px solid #f0f0f0; */
 }
 
 .section-title {

+ 105 - 170
web/src/views/content/aiTagging/taggingLogs/index.vue

@@ -2,16 +2,7 @@
   <div class="tagging-logs-container">
     <!-- 顶部搜索栏 -->
     <div class="search-bar">
-      <el-form :inline="true" :model="searchForm" class="search-form">
-        <el-form-item label="请求ID:">
-          <el-input v-model="searchForm.requestId" placeholder="请输入" style="width: 200px;"></el-input>
-        </el-form-item>
-        <el-form-item label="贷款申请编号:">
-          <el-input v-model="searchForm.loanApplyNo" placeholder="请输入" style="width: 200px;"></el-input>
-        </el-form-item>
-        <el-form-item label="合同编号:">
-          <el-input v-model="searchForm.contractNo" placeholder="请输入" style="width: 200px;"></el-input>
-        </el-form-item>
+      <el-form :inline="true" :model="searchForm" label-width="110px">
         <el-form-item label="调用时间:">
           <el-date-picker
             v-model="searchForm.callTime"
@@ -22,30 +13,11 @@
             style="width: 240px;"
           ></el-date-picker>
         </el-form-item>
-        <el-form-item label="接口:">
-          <el-select v-model="searchForm.apiType" placeholder="全部" style="width: 150px;">
-            <el-option label="全部" value=""></el-option>
-            <el-option label="getCustomerTags" value="getCustomerTags"></el-option>
-            <el-option label="queryCustomerTags" value="queryCustomerTags"></el-option>
-            <el-option label="feedbackTagsResult" value="feedbackTagsResult"></el-option>
-          </el-select>
-        </el-form-item>
-        <el-form-item label="状态:">
-          <el-select v-model="searchForm.status" placeholder="全部" style="width: 150px;">
-            <el-option label="全部" value=""></el-option>
-            <el-option label="成功" value="success"></el-option>
-            <el-option label="失败" value="failed"></el-option>
-            <el-option label="响应中" value="pending"></el-option>
-          </el-select>
-        </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="handleSearch">查询</el-button>
         </el-form-item>
         <el-form-item>
-          <el-button @click="handleReset">重置</el-button>
-        </el-form-item>
-        <el-form-item>
-          <el-button @click="handleRefresh">刷新</el-button>
+          <el-button type="" plain @click="handleReset">重置</el-button>
         </el-form-item>
       </el-form>
     </div>
@@ -55,16 +27,10 @@
       <!-- 数据表格 -->
       <div class="table-container">
         <el-table :data="logs" style="width: 100%">
-          <el-table-column prop="requestId" label="请求ID" min-width="180"></el-table-column>
-          <el-table-column prop="loanApplyNo" label="贷款申请编号" min-width="150"></el-table-column>
-          <el-table-column prop="contractNo" label="合同编号" min-width="150"></el-table-column>
-          <el-table-column prop="apiName" label="接口" min-width="150"></el-table-column>
-          <el-table-column prop="callTime" label="调用时间" min-width="180"></el-table-column>
-          <el-table-column prop="status" label="状态" min-width="100">
-            <template slot-scope="scope">
-              <el-tag :type="getStatusType(scope.row.status)">{{ scope.row.status }}</el-tag>
-            </template>
-          </el-table-column>
+          <el-table-column prop="userName" label="用户名称" min-width="120"></el-table-column>
+          <el-table-column prop="userId" label="用户id" min-width="180"></el-table-column>
+          <el-table-column prop="operationType" label="操作类型" min-width="120"></el-table-column>
+          <el-table-column prop="operationTime" label="操作时间" min-width="180"></el-table-column>
           <el-table-column prop="action" label="操作" min-width="100">
             <template slot-scope="scope">
               <el-button type="text" @click="handleViewDetail(scope.row)">查看详情</el-button>
@@ -74,7 +40,7 @@
       </div>
 
       <!-- 分页控件 -->
-      <div class="pagination-container">
+      <div class="pagination">
         <el-pagination
           :current-page="currentPage"
           :page-size="pageSize"
@@ -108,95 +74,90 @@ export default {
     return {
       // 搜索表单
       searchForm: {
-        requestId: '',
-        loanApplyNo: '',
-        contractNo: '',
-        callTime: '',
-        apiType: '',
-        status: ''
+        callTime: ''
       },
       
       // 日志列表
       logs: [
         {
-          requestId: 'API-20260203-87654',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'getCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '成功'
+          userName: '张三',
+          userId: 'ks139914512123',
+          operationType: '用户登录',
+          operationTime: '2026-02-03 15:39:35',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87653',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'queryCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '成功'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '修改标签',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87652',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'feedbackTagsResult',
-          callTime: '2023-01-01 11:11:11',
-          status: '失败'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '删除标签',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87651',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'getCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '响应中'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '新建标签',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87650',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'getCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '成功'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '标签查询',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87649',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'getCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '成功'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '用户登录',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87648',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'getCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '成功'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '修改标签',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87647',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'getCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '成功'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '删除标签',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87646',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'getCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '成功'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '新建标签',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         },
         {
-          requestId: 'API-20260203-87645',
-          loanApplyNo: 'DKSQ20260203001',
-          contractNo: 'CUST20260203001',
-          apiName: 'getCustomerTags',
-          callTime: '2023-01-01 11:11:11',
-          status: '成功'
+          userName: '张三',
+          userId: 'DKSQ20260203001',
+          operationType: '标签查询',
+          operationTime: '2023-01-01 11:11:11',
+          input: '{"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"}',
+          output: '{"Success"}'
         }
       ],
       
@@ -211,19 +172,7 @@ export default {
     }
   },
   methods: {
-    // 根据状态获取标签类型
-    getStatusType(status) {
-      switch (status) {
-        case '成功':
-          return 'success'
-        case '失败':
-          return 'danger'
-        case '响应中':
-          return 'warning'
-        default:
-          return ''
-      }
-    },
+
     
     // 搜索日志
     handleSearch() {
@@ -235,12 +184,7 @@ export default {
     // 重置搜索
     handleReset() {
       this.searchForm = {
-        requestId: '',
-        loanApplyNo: '',
-        contractNo: '',
-        callTime: '',
-        apiType: '',
-        status: ''
+        callTime: ''
       }
       console.log('重置搜索')
     },
@@ -255,41 +199,14 @@ export default {
     // 查看详情
     handleViewDetail(row) {
       console.log('查看详情:', row)
-      // 模拟加载日志详情数据
+      // 构建与LogDetailDrawer.vue期望结构一致的详情数据
       this.currentLogDetail = {
-        callTime: '2026-02-03 15:30:45',
-        responseTime: '124ms',
-        requestId: row.requestId,
-        apiName: row.apiName,
-        status: row.status,
-        clientIp: '192.168.1.45',
-        requestMethod: 'POST',
-        requestUrl: '/api/user/login',
-        requestHeaders: {
-          'Content-Type': 'application/json',
-          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
-        },
-        requestBody: {
-          username: 'testuser',
-          password: '********'
-        },
-        responseStatus: 'HTTP 200',
-        responseHeaders: {
-          'Content-Type': 'application/json',
-          'X-Request-Id': row.requestId
-        },
-        responseBody: {
-          code: 0,
-          message: '登录成功',
-          data: {
-            token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
-            userInfo: {
-              id: '1001',
-              username: 'testuser',
-              role: 'user'
-            }
-          }
-        }
+        userName: row.userName,
+        userId: row.userId,
+        operationType: row.operationType,
+        operationTime: row.operationTime,
+        input: row.input,
+        output: row.output
       }
       this.drawerVisible = true
     },
@@ -315,7 +232,7 @@ export default {
 .tagging-logs-container {
   padding: 0;
   background-color: transparent;
-  min-height: 100vh;
+  height: 100%;
 }
 
 /* 搜索栏样式 */
@@ -327,11 +244,28 @@ export default {
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
 }
 
-.search-form {
+.search-row {
   display: flex;
-  flex-wrap: wrap;
   align-items: center;
-  gap: 16px;
+  margin-bottom: 16px;
+}
+
+.search-row:last-child {
+  margin-bottom: 0;
+  justify-content: flex-end;
+}
+
+.search-row .el-form-item {
+  margin-right: 32px;
+  margin-bottom: 0;
+}
+
+.search-row .el-form-item:last-child {
+  margin-right: 0;
+}
+
+.search-row .el-button {
+  margin-left: 12px;
 }
 
 /* 表格和分页容器 */
@@ -348,13 +282,14 @@ export default {
   padding: 20px 20px 10px;
 }
 
-/* 分页控件 */
-.pagination-container {
+/* 分页 */
+.pagination {
   display: flex;
   justify-content: flex-end;
   align-items: center;
-  padding: 0 20px 20px;
-  /* border-top: 1px solid #f0f0f0; */
+}
+.pagination .el-pagination{
+  padding: 10px 20px;
 }
 
 /* 响应式设计 */
@@ -373,11 +308,11 @@ export default {
 
   .search-bar,
   .table-container,
-  .pagination-container {
+  .pagination {
     padding: 10px;
   }
 
-  .pagination-container {
+  .pagination {
     flex-direction: column;
     align-items: flex-start;
     gap: 16px;

+ 6 - 9
web/src/views/content/aiTagging/taggingResults/components/Detail.vue

@@ -42,7 +42,7 @@
     </div>
 
     <!-- 分页控件 -->
-    <div class="pagination-container">
+    <div class="pagination">
       <el-pagination
         :current-page="currentDetailPage"
         :page-size="detailPageSize"
@@ -165,17 +165,14 @@ export default {
   margin-bottom: 8px;
 }
 
-/* 分页控件 */
-.pagination-container {
+/* 分页 */
+.pagination {
   display: flex;
   justify-content: flex-end;
   align-items: center;
-  padding:0 20px 20px;
 }
-
-.total-count {
-  font-size: 14px;
-  color: #606266;
+.pagination .el-pagination{
+  padding: 10px 20px;
 }
 
 /* 响应式设计 */
@@ -186,7 +183,7 @@ export default {
     gap: 12px;
   }
 
-  .pagination-container {
+  .pagination {
     flex-direction: column;
     align-items: flex-start;
     gap: 16px;

+ 1 - 1
web/src/views/content/aiTagging/taggingResults/components/Overview.vue

@@ -243,7 +243,7 @@ export default {
   grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
   gap: 20px;
   padding: 20px;
-  margin-bottom: 20px;
+  /* margin-bottom: 20px; */
 }
 
 /* 统计指标项 */

+ 3 - 3
web/src/views/content/aiTagging/taggingResults/index.vue

@@ -272,9 +272,9 @@ export default {
 
 <style scoped>
 .tagging-results-container {
-  padding: 20px;
-  background-color: #f0f2f5;
-  min-height: 100vh;
+  padding: 0;
+  background-color: transparent;
+  height: 100%;
 }
 
 /* 搜索栏样式 */

+ 1 - 1
web/src/views/content/aiTagging/taggingSystemManage/TagSystemEdit.vue

@@ -193,7 +193,7 @@ export default {
 .edit-page {
   padding: 0;
   background-color: transparent;
-  min-height: 100vh;
+  height: 100%;
 }
 
 .edit-header {

+ 28 - 4
web/src/views/content/aiTagging/taggingSystemManage/components/CreateTagSystem.vue

@@ -117,11 +117,35 @@ export default {
         if (valid) {
           console.log(this.isEditMode ? '编辑标签体系:' : '创建标签体系:', this.form);
           
-          // 触发父组件的对应事件
-          this.$emit(this.isEditMode ? 'edit' : 'create', this.form);
+          // 构建请求参数
+          const requestData = this.isEditMode ? {
+            id: this.form.id,
+            categoryNm: this.form.name,
+            categoryDesc: this.form.description
+          } : {
+            categoryNm: this.form.name,
+            categoryDesc: this.form.description
+          };
           
-          // 重置表单
-          this.resetForm();
+          // 调用后端接口
+          yufp.service.request({
+            url: backend.tagServer + (this.isEditMode ? "/api/aitag-tagcategory/update" : "/api/aitag-tagcategory/create"),
+            method: 'post',
+            data: requestData,
+            callback: (code, error, response) => {
+              if (response.code == '0') {
+                this.$message.success(this.isEditMode ? '标签体系编辑成功' : '标签体系创建成功');
+                
+                // 重置表单
+                this.resetForm();
+                
+                // 触发父组件的成功事件
+                this.$emit('success');
+              } else {
+                this.$message.error(response.message || (this.isEditMode ? '编辑标签体系失败' : '创建标签体系失败'));
+              }
+            }
+          });
         } else {
           console.log('表单验证失败');
           return false;

+ 107 - 63
web/src/views/content/aiTagging/taggingSystemManage/index.vue

@@ -3,7 +3,7 @@
     <!-- 顶部搜索栏 -->
     <div class="search-bar">
       <el-form :inline="true" :model="searchForm" class="search-form">
-        <el-form-item label="123123标签体系名称:">
+        <el-form-item label="标签体系名称:">
           <el-input v-model="searchForm.name" placeholder="请输入" style="width: 300px;"></el-input>
         </el-form-item>
         <el-form-item>
@@ -61,13 +61,12 @@
     </div>
 
     <!-- 分页控件 -->
-    <div class="pagination-container">
-      <div class="total-count">共 {{ totalCount }} 条数据</div>
+    <div class="pagination">
       <el-pagination
         :current-page="currentPage"
         :page-size="pageSize"
         :page-sizes="[10, 20, 50]"
-        layout="prev, pager, next"
+        layout="total, sizes, prev, pager, next, jumper"
         :total="totalCount"
         @size-change="handleSizeChange"
         @current-change="handleCurrentChange"
@@ -77,7 +76,7 @@
     <!-- 创建标签体系对话框 -->
     <CreateTagSystem
       :visible="createDialogVisible"
-      @create="handleTagSystemCreate"
+      @success="handleCreateSuccess"
       @cancel="handleCreateCancel"
     />
     
@@ -86,7 +85,7 @@
       :visible="editDialogVisible"
       :is-edit-mode="true"
       :edit-data="currentEditSystem"
-      @edit="handleTagSystemEdit"
+      @success="handleEditSuccess"
       @cancel="handleEditCancel"
     />
   </div>
@@ -165,17 +164,43 @@ export default {
       currentEditSystem: {}
     }
   },
+  mounted() {
+    // 默认加载标签体系列表
+    this.loadTagSystems();
+  },
   methods: {
+    // 加载标签体系列表
+    loadTagSystems() {
+      yufp.service.request({
+        url: backend.tagServer + "/api/aitag-category/list",
+        method: 'get',
+        data: {
+          name: this.searchForm.name,
+          page: this.currentPage,
+          pageSize: this.pageSize
+        },
+        callback: (code, error, response) => {
+          if (response.code == '0') {
+            this.tagSystems = response.data || [];
+            this.totalCount = response.total || 0;
+          } else {
+            this.$message.error(response.message || '获取标签体系列表失败');
+          }
+        }
+      });
+    },
     // 搜索标签体系
     handleSearch() {
       console.log('搜索标签体系:', this.searchForm.name)
-      // 这里可以调用后端接口进行搜索
-      this.$message.success('搜索成功')
+      this.currentPage = 1;
+      this.loadTagSystems();
     },
 
     // 重置搜索
     handleReset() {
       this.searchForm.name = ''
+      this.currentPage = 1;
+      this.loadTagSystems();
       console.log('重置搜索')
     },
 
@@ -185,29 +210,11 @@ export default {
       this.createDialogVisible = true
     },
     
-    // 处理标签体系创建
-    handleTagSystemCreate(formData) {
-      console.log('创建标签体系:', formData)
-      
-      // 模拟创建标签体系的逻辑
-      const newSystem = {
-        id: Date.now(),
-        name: formData.name,
-        description: formData.description,
-        status: 'enabled',
-        tagCount: 0,
-        createDate: new Date().toISOString().split('T')[0]
-      }
-      
-      // 添加到标签体系列表
-      this.tagSystems.unshift(newSystem)
-      this.totalCount++
-      
-      // 显示成功消息
-      this.$message.success('标签体系创建成功')
-      
-      // 关闭对话框
+    // 处理创建成功
+    handleCreateSuccess() {
+      console.log('标签体系创建成功')
       this.createDialogVisible = false
+      this.loadTagSystems();
     },
     
     // 处理创建取消
@@ -223,19 +230,11 @@ export default {
       this.editDialogVisible = true
     },
     
-    // 处理标签体系编辑
-    handleTagSystemEdit(formData) {
-      console.log('编辑标签体系:', formData)
-      
-      // 找到并更新标签体系
-      const index = this.tagSystems.findIndex(system => system.id === formData.id)
-      if (index !== -1) {
-        this.tagSystems[index] = { ...formData }
-        this.$message.success('标签体系编辑成功')
-      }
-      
-      // 关闭对话框
+    // 处理编辑成功
+    handleEditSuccess() {
+      console.log('标签体系编辑成功')
       this.editDialogVisible = false
+      this.loadTagSystems();
     },
     
     // 处理编辑取消
@@ -264,15 +263,49 @@ export default {
     // 启用标签体系
     handleEnableTagSystem(system) {
       console.log('启用标签体系:', system.name)
-      system.status = 'enabled'
-      this.$message.success(`启用标签体系: ${system.name}`)
+      
+      // 调用后端接口启用标签体系
+      yufp.service.request({
+        url: backend.tagServer + "/api/aitag-tagcategory/enable",
+        method: 'post',
+        data: {
+          id: system.id
+        },
+        callback: (code, error, response) => {
+          if (response.code == '0') {
+            this.$message.success(`启用标签体系: ${system.name}`)
+            
+            // 重新加载标签体系列表
+            this.loadTagSystems();
+          } else {
+            this.$message.error(response.message || '启用标签体系失败');
+          }
+        }
+      });
     },
 
     // 停用标签体系
     handleDisableTagSystem(system) {
       console.log('停用标签体系:', system.name)
-      system.status = 'disabled'
-      this.$message.success(`停用标签体系: ${system.name}`)
+      
+      // 调用后端接口停用标签体系
+      yufp.service.request({
+        url: backend.tagServer + "/api/aitag-tagcategory/disable",
+        method: 'post',
+        data: {
+          id: system.id
+        },
+        callback: (code, error, response) => {
+          if (response.code == '0') {
+            this.$message.success(`停用标签体系: ${system.name}`)
+            
+            // 重新加载标签体系列表
+            this.loadTagSystems();
+          } else {
+            this.$message.error(response.message || '停用标签体系失败');
+          }
+        }
+      });
     },
 
     // 删除标签体系
@@ -283,8 +316,25 @@ export default {
         type: 'warning'
       }).then(() => {
         console.log('删除标签体系:', system.name)
-        // 这里可以调用后端接口删除标签体系
-        this.$message.success(`删除标签体系: ${system.name}`)
+        
+        // 调用后端接口删除标签体系
+        yufp.service.request({
+          url: backend.tagServer + "/api/aitag-tagcategory/delete",
+          method: 'post',
+          data: {
+            id: system.id
+          },
+          callback: (code, error, response) => {
+            if (response.code == '0') {
+              this.$message.success(`删除标签体系: ${system.name}`)
+              
+              // 重新加载标签体系列表
+              this.loadTagSystems();
+            } else {
+              this.$message.error(response.message || '删除标签体系失败');
+            }
+          }
+        });
       }).catch(() => {
         console.log('取消删除标签体系:', system.name)
       })
@@ -306,14 +356,14 @@ export default {
     handleSizeChange(size) {
       console.log('每页条数:', size)
       this.pageSize = size
-      // 这里可以重新加载数据
+      this.loadTagSystems();
     },
 
     // 当前页码变化
     handleCurrentChange(current) {
       console.log('当前页码:', current)
       this.currentPage = current
-      // 这里可以重新加载数据
+      this.loadTagSystems();
     }
   }
 }
@@ -323,7 +373,7 @@ export default {
 .tag-system-container {
   padding: 0;
   background-color: transparent;
-  min-height: 100vh;
+  height: 100%;
 }
 
 /* 搜索栏样式 */
@@ -469,20 +519,14 @@ export default {
   padding-top: 16px;
 }
 
-/* 分页控件 */
-.pagination-container {
+/* 分页 */
+.pagination {
   display: flex;
-  justify-content: space-between;
+  justify-content: flex-end;
   align-items: center;
-  background-color: #fff;
-  padding: 20px;
-  border-radius: 8px;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
 }
-
-.total-count {
-  font-size: 14px;
-  color: #606266;
+.pagination .el-pagination{
+  padding: 10px 20px;
 }
 
 /* 响应式设计 */
@@ -508,7 +552,7 @@ export default {
     gap: 12px;
   }
 
-  .pagination-container {
+  .pagination {
     flex-direction: column;
     align-items: flex-start;
     gap: 16px;

+ 208 - 0
web/src/views/content/aiTagging/utils/common.js

@@ -0,0 +1,208 @@
+/**
+ * 公共工具方法
+ */
+
+/**
+ * 复制文本到剪贴板
+ * @param {string} text - 要复制的文本
+ * @param {Object} vueInstance - Vue实例,用于显示消息提示
+ * @returns {Promise<boolean>} - 复制是否成功
+ */
+export function copyToClipboard(text, vueInstance = null) {
+  return new Promise((resolve, reject) => {
+    // 确保文本存在
+    if (!text) {
+      if (vueInstance) {
+        vueInstance.$message.error('复制内容为空');
+      }
+      reject(new Error('复制内容为空'));
+      return;
+    }
+
+    const copyText = String(text);
+    console.log('尝试复制文本:', copyText);
+
+    // 尝试使用现代Clipboard API
+    if (navigator.clipboard) {
+      console.log('使用现代Clipboard API');
+      navigator.clipboard.writeText(copyText)
+        .then(() => {
+          console.log('复制成功');
+          if (vueInstance) {
+            vueInstance.$message.success('复制成功');
+          }
+          resolve(true);
+        })
+        .catch(err => {
+          console.error('Clipboard API 错误:', err);
+          // 降级到传统方法
+          fallbackCopyTextToClipboard(copyText, vueInstance, resolve, reject);
+        });
+    } else {
+      // 直接使用传统方法
+      fallbackCopyTextToClipboard(copyText, vueInstance, resolve, reject);
+    }
+  });
+}
+
+/**
+ * 传统复制方法(降级方案)
+ * @param {string} text - 要复制的文本
+ * @param {Object} vueInstance - Vue实例,用于显示消息提示
+ * @param {Function} resolve - Promise resolve函数
+ * @param {Function} reject - Promise reject函数
+ */
+function fallbackCopyTextToClipboard(text, vueInstance, resolve, reject) {
+  console.log('使用传统复制方法');
+
+  // 创建textarea元素
+  const textArea = document.createElement('textarea');
+  textArea.value = text;
+
+  // 确保textarea不在可视区域内
+  textArea.style.position = 'fixed';
+  textArea.style.left = '-999999px';
+  textArea.style.top = '-999999px';
+  textArea.style.width = '2em';
+  textArea.style.height = '2em';
+  textArea.style.padding = '0';
+  textArea.style.border = 'none';
+  textArea.style.outline = 'none';
+  textArea.style.boxShadow = 'none';
+  textArea.style.background = 'transparent';
+
+  // 添加到DOM
+  document.body.appendChild(textArea);
+
+  try {
+    // 选择文本
+    textArea.focus();
+    textArea.select();
+
+    // 执行复制命令
+    const successful = document.execCommand('copy');
+    console.log('传统方法复制结果:', successful);
+
+    if (successful) {
+      if (vueInstance) {
+        vueInstance.$message.success('复制成功');
+      }
+      resolve(true);
+    } else {
+      if (vueInstance) {
+        vueInstance.$message.error('复制失败,请手动复制');
+      }
+      reject(new Error('复制失败'));
+    }
+  } catch (err) {
+    console.error('复制失败:', err);
+    if (vueInstance) {
+      vueInstance.$message.error('复制失败,请手动复制');
+    }
+    reject(err);
+  } finally {
+    // 清理临时元素
+    setTimeout(() => {
+      document.body.removeChild(textArea);
+    }, 100);
+  }
+}
+
+/**
+ * 显示手动复制界面(最终降级方案)
+ * @param {string} text - 要复制的文本
+ * @param {Object} vueInstance - Vue实例,用于显示消息提示
+ */
+export function showManualCopyDialog(text, vueInstance = null) {
+  if (!text) {
+    if (vueInstance) {
+      vueInstance.$message.error('复制内容为空');
+    }
+    return;
+  }
+
+  console.log('显示手动复制界面');
+
+  // 创建一个临时的div来显示文本,让用户手动复制
+  const tempDiv = document.createElement('div');
+  tempDiv.style.position = 'fixed';
+  tempDiv.style.top = '50%';
+  tempDiv.style.left = '50%';
+  tempDiv.style.transform = 'translate(-50%, -50%)';
+  tempDiv.style.background = 'white';
+  tempDiv.style.border = '1px solid #ddd';
+  tempDiv.style.borderRadius = '8px';
+  tempDiv.style.padding = '20px';
+  tempDiv.style.boxShadow = '0 2px 12px 0 rgba(0, 0, 0, 0.1)';
+  tempDiv.style.zIndex = '9999';
+  tempDiv.style.minWidth = '300px';
+
+  tempDiv.innerHTML = `
+    <div style="margin-bottom: 15px;">
+      <p style="margin: 0 0 10px 0; font-weight: bold;">复制内容</p>
+      <input type="text" value="${text}" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-family: monospace;" id="temp-copy-input">
+    </div>
+    <div style="display: flex; gap: 10px; justify-content: flex-end;">
+      <button style="padding: 6px 12px; border: 1px solid #ddd; border-radius: 4px; background: white; cursor: pointer;" id="temp-copy-btn">复制</button>
+      <button style="padding: 6px 12px; border: 1px solid #ddd; border-radius: 4px; background: white; cursor: pointer;" id="temp-close-btn">关闭</button>
+    </div>
+  `;
+
+  document.body.appendChild(tempDiv);
+
+  // 获取元素
+  const input = document.getElementById('temp-copy-input');
+  const copyBtn = document.getElementById('temp-copy-btn');
+  const closeBtn = document.getElementById('temp-close-btn');
+
+  // 自动选择文本
+  input.select();
+
+  // 复制按钮点击事件
+  copyBtn.addEventListener('click', () => {
+    input.select();
+    try {
+      const successful = document.execCommand('copy');
+      if (successful) {
+        if (vueInstance) {
+          vueInstance.$message.success('复制成功');
+        }
+      } else {
+        if (vueInstance) {
+          vueInstance.$message.error('复制失败,请手动复制');
+        }
+      }
+    } catch (err) {
+      console.error('复制失败:', err);
+      if (vueInstance) {
+        vueInstance.$message.error('复制失败,请手动复制');
+      }
+    }
+  });
+
+  // 关闭按钮点击事件
+  closeBtn.addEventListener('click', () => {
+    document.body.removeChild(tempDiv);
+  });
+
+  // 点击外部关闭
+  tempDiv.addEventListener('click', (e) => {
+    if (e.target === tempDiv) {
+      document.body.removeChild(tempDiv);
+    }
+  });
+}
+
+/**
+ * 生成随机字符串
+ * @param {number} length - 字符串长度
+ * @returns {string} - 随机字符串
+ */
+export function generateRandomString(length = 20) {
+  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+  let result = '';
+  for (let i = 0; i < length; i++) {
+    result += chars.charAt(Math.floor(Math.random() * chars.length));
+  }
+  return result;
+}

+ 1 - 2
web/src/views/content/workstation/workstation/workstation.vue

@@ -486,13 +486,12 @@
 			init(){
 				this.loading = true;
 				yufp.service.request({
-					url: this.url.getUserQuickMenu,
+					url: backend.tagServer + "/api/tab-app/list",
 					method: 'get',
 					data:{
 						sysId:yufp.session.logicSys.id,
 					},
 					callback: (code, error, response) => {
-						this.loading = false;
 						if (response.code == '0') {
 							this.list = response.data;
 						} else {