From 009c4aa11e33f60c4d35eaa664fb26211ba02331 Mon Sep 17 00:00:00 2001 From: xueyinfei <1207092115@qq.com> Date: Fri, 2 Jan 2026 02:40:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/sscf_controller.py | 20 ++- .../module_admin/dao/sscf_dao.py | 31 +++- .../module_admin/service/cdplb_service.py | 4 +- .../module_admin/service/sscf_service.py | 125 +++++++++++++++- .../src/views/dataint/cypz/cdplb.vue | 4 +- .../src/views/dataint/sscf/index.vue | 136 +++++++++++++++++- 6 files changed, 309 insertions(+), 11 deletions(-) diff --git a/vue-fastapi-backend/module_admin/controller/sscf_controller.py b/vue-fastapi-backend/module_admin/controller/sscf_controller.py index ffaec16..32c9de9 100644 --- a/vue-fastapi-backend/module_admin/controller/sscf_controller.py +++ b/vue-fastapi-backend/module_admin/controller/sscf_controller.py @@ -1,6 +1,6 @@ from typing import List -from fastapi import APIRouter, Depends, Request +from fastapi import APIRouter, Depends, Request, UploadFile, File, Query from sqlalchemy.ext.asyncio import AsyncSession from config.get_db import get_db from module_admin.entity.vo.user_vo import CurrentUserModel @@ -8,6 +8,7 @@ from module_admin.entity.vo.dataint_vo import SscfPageObject, SaveSscfModel, Tre from module_admin.service.login_service import LoginService from module_admin.service.sscf_service import SscfService from utils.response_util import ResponseUtil +from utils.common_util import bytes2file_response sscfController = APIRouter(prefix='/dataint/sscf', dependencies=[Depends(LoginService.get_current_user)]) @@ -53,3 +54,20 @@ async def delete_tsmcb(request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user)): result = await SscfService.delete_sscf(query_db, array) return ResponseUtil.success(msg=result.message) + + +@sscfController.post("/importTemplate") +async def export_sscf_template(request: Request, query_db: AsyncSession = Depends(get_db)): + meta_import_template_result = await SscfService.get_import_template_services() + return ResponseUtil.streaming(data=bytes2file_response(meta_import_template_result)) + + +@sscfController.post("/upload") +async def batch_import_sscf_data( + request: Request, + file: UploadFile = File(...), + overWrite: bool = Query(alias='overWrite'), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + batch_import_result = await SscfService.batch_import_sscf_data(query_db, file, overWrite, current_user) + return ResponseUtil.success(data=batch_import_result) \ No newline at end of file diff --git a/vue-fastapi-backend/module_admin/dao/sscf_dao.py b/vue-fastapi-backend/module_admin/dao/sscf_dao.py index 5e57af8..61f9cf7 100644 --- a/vue-fastapi-backend/module_admin/dao/sscf_dao.py +++ b/vue-fastapi-backend/module_admin/dao/sscf_dao.py @@ -4,7 +4,7 @@ from typing import List from sqlalchemy import desc, delete, func, select, update from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.vo.user_vo import CurrentUserModel -from module_admin.entity.vo.dataint_vo import SscfPageObject, TreeOperateModel +from module_admin.entity.vo.dataint_vo import SscfPageObject, TreeOperateModel, SaveSscfModel from module_admin.entity.do.dataint_do import SysSscf, SysDassetTree from sqlalchemy import select, text, cast, Integer, and_, or_, outerjoin, func, join from utils.page_util import PageUtil @@ -45,6 +45,24 @@ class SscfDao: ) return result + @classmethod + async def get_oldSscf(cls, db: AsyncSession, sscf: SaveSscfModel): + result = ( + ( + await db.execute( + select(SysSscf).where(SysSscf.dasset_id == sscf.dasset_id, + SysSscf.keyword == sscf.keyword, + SysSscf.algorithm == sscf.algorithm, + SysSscf.order == sscf.order, + SysSscf.whole_sentence == sscf.whole_sentence, + SysSscf.type == sscf.type, + SysSscf.supp_expl == sscf.supp_expl, + ).distinct() + ) + ).scalars().first() + ) + return result + @classmethod async def update_sscf(cls, db: AsyncSession, saveObj: dict): await db.execute(update(SysSscf), [saveObj]) @@ -64,6 +82,17 @@ class SscfDao: ) return result + @classmethod + async def getDassetIdByName(cls, db: AsyncSession, name: str): + result = ( + ( + await db.execute( + select(SysDassetTree).where(SysDassetTree.dasset_code == name).distinct() + ) + ).scalars().first() + ) + return result + @classmethod async def get_dasset_tree_by_code(cls, db: AsyncSession, code: str): result = ( diff --git a/vue-fastapi-backend/module_admin/service/cdplb_service.py b/vue-fastapi-backend/module_admin/service/cdplb_service.py index 9011516..1ec8c5e 100644 --- a/vue-fastapi-backend/module_admin/service/cdplb_service.py +++ b/vue-fastapi-backend/module_admin/service/cdplb_service.py @@ -127,9 +127,9 @@ class CdplbService: noneValid += "批量对象表名不能为空" if row['bath_obj_fld_name'] is None or len(row['bath_obj_fld_name']) == 0: if len(noneValid) > 0: - noneValid += ",批里对象字段名不能为空" + noneValid += ",批量对象字段名不能为空" else: - noneValid += "批里对象字段名不能为空" + noneValid += "批量对象字段名不能为空" if row['ssys_cd'] is None or len(row['ssys_cd']) == 0: if len(noneValid) > 0: noneValid += ",系统不能为空" diff --git a/vue-fastapi-backend/module_admin/service/sscf_service.py b/vue-fastapi-backend/module_admin/service/sscf_service.py index fcaca73..db9c752 100644 --- a/vue-fastapi-backend/module_admin/service/sscf_service.py +++ b/vue-fastapi-backend/module_admin/service/sscf_service.py @@ -1,7 +1,11 @@ +import io import json import uuid from typing import Optional, List + +import pandas as pd +from fastapi import UploadFile from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.entity.vo.user_vo import CurrentUserModel @@ -10,7 +14,8 @@ from module_admin.entity.do.dataint_do import SysSscf from module_admin.dao.sscf_dao import SscfDao from exceptions.exception import ServiceException, ServiceWarning from datetime import datetime -from utils.common_util import CamelCaseUtil +from utils.common_util import * + class SscfService: @@ -94,3 +99,121 @@ class SscfService: await db.commit() return CrudResponseModel(is_success=True, message='操作成功') + @staticmethod + async def get_import_template_services(): + """ + 获取元数据导入模板service + :return: 元数据导入模板excel的二进制数据 + """ + table_header_list = ['归属资产名', '关键词', '算法', '按顺序匹配标志', '整句', '类型', '补充说明', '状态'] + selector_header_list = ['算法', '按顺序匹配标志', '整句', '类型', '状态'] + option_list = [{'算法': ['包含', '等于'], '按顺序匹配标志': ['是', '否'], '整句': ['是', '否'], '类型': ['补充', '替换'], '状态': ['正常', '停用']}] + + sheet_config1 = dict( + sheet_name="短句配置", header_list=table_header_list, data_list=[], selector_header_list=selector_header_list + ) + + sheet_configs = [sheet_config1] + binary_data = get_excel_template_with_sheets( + sheet_configs, # 每个Sheet的配置(包含表头、选择器等) + option_list + ) + + return binary_data + + + @classmethod + async def batch_import_sscf_data(cls, + result_db: AsyncSession, + file: UploadFile, + overWrite: bool, + current_user: CurrentUserModel): + table_header_dict = { + '归属资产名': 'dassetName', + '关键词': 'keyword', + '算法': 'algorithm', + '按顺序匹配标志': 'order', + '整句': 'wholeSentence', + '类型': 'type', + '补充说明': 'suppExpl', + '状态': 'status' + } + contents = await file.read() + excel_file = pd.ExcelFile(io.BytesIO(contents)) + await file.close() + # 获取所有sheet名称 + sheet_names = excel_file.sheet_names + # 逐个读取 + tableSheet = sheet_names[0] + result_list = { + "rows": [], + "successCount": 0 + } + if tableSheet == '短句配置': + df = excel_file.parse(sheet_name=tableSheet, dtype=str, keep_default_na=False, na_values=[]) + df.rename(columns=table_header_dict, inplace=True) + for index, row in df.iterrows(): + noneValid = '' + if row['dassetName'] is None or len(row['dassetName']) == 0: + noneValid += "归属资产名不能为空" + if row['keyword'] is None or len(row['keyword']) == 0: + if len(noneValid) > 0: + noneValid += ",关键词不能为空" + else: + noneValid += "关键词不能为空" + if row['algorithm'] is None or len(row['algorithm']) == 0: + if len(noneValid) > 0: + noneValid += ",算法不能为空" + else: + noneValid += "算法不能为空" + if row['order'] is None or len(row['order']) == 0: + if len(noneValid) > 0: + noneValid += ",按顺序匹配标志不能为空" + else: + noneValid += "按顺序匹配标志不能为空" + if row['wholeSentence'] is None or len(row['wholeSentence']) == 0: + if len(noneValid) > 0: + noneValid += ",整句不能为空" + else: + noneValid += "整句不能为空" + if row['type'] is None or len(row['type']) == 0: + if len(noneValid) > 0: + noneValid += ",类型不能为空" + else: + noneValid += "类型不能为空" + if row['status'] is None or len(row['status']) == 0: + if len(noneValid) > 0: + noneValid += ",状态不能为空" + else: + noneValid += "状态不能为空" + dasset = await SscfDao.getDassetIdByName(result_db, row['dassetName']) + if dasset is None: + if len(noneValid) > 0: + noneValid += ",归属资产名为无效名称(找不到对应资产目录)" + else: + noneValid += "归属资产名为无效名称(找不到对应资产目录)" + if len(noneValid) > 0: + result_list['rows'].append({ + "row": index + 2, + "errorInfo": noneValid + }) + continue + sscf = SaveSscfModel() + sscf.dasset_id = dasset.onum, + sscf.keyword = row['keyword'] + sscf.algorithm = row['algorithm'] + sscf.order = 'True' if row['order'] == '是' else 'False' + sscf.whole_sentence = 'True' if row['wholeSentence'] == '是' else 'False' + sscf.type = row['type'] + sscf.supp_expl = row['suppExpl'] + sscf.status = '1' if row['status'] == '正常' else '0' + oldSscf =await SscfDao.get_oldSscf(result_db, sscf) + if oldSscf is not None: + sscf.onum = oldSscf.onum + await cls.save_sscf(result_db, sscf, current_user) + result_list['successCount'] += 1 + return result_list + + + + diff --git a/vue-fastapi-frontend/src/views/dataint/cypz/cdplb.vue b/vue-fastapi-frontend/src/views/dataint/cypz/cdplb.vue index 4d4b60f..947c75a 100644 --- a/vue-fastapi-frontend/src/views/dataint/cypz/cdplb.vue +++ b/vue-fastapi-frontend/src/views/dataint/cypz/cdplb.vue @@ -534,8 +534,8 @@ function handleExport(){ if (dataList.value.length > 0){ for (let i = 0; i < dataList.value.length; i++) { data.push({ - "系统":getSrcSysName(dassetList.value[i].ssysId), - "模式":dassetList.value[i].mdlName, + "系统":getSrcSysName(dataList.value[i].ssysId), + "模式":dataList.value[i].mdlName, "批量对象表名":dataList.value[i].bathObjTabName, "批里对象字段名":dataList.value[i].bathObjFldName, "状态":dataList.value[i].status === '1'?"正常":"停用" diff --git a/vue-fastapi-frontend/src/views/dataint/sscf/index.vue b/vue-fastapi-frontend/src/views/dataint/sscf/index.vue index adabd77..025b480 100644 --- a/vue-fastapi-frontend/src/views/dataint/sscf/index.vue +++ b/vue-fastapi-frontend/src/views/dataint/sscf/index.vue @@ -246,11 +246,75 @@ + + + +
将文件拖到此处,或点击上传
+ +
+ +
+ + + +