si@aidatagov.com 3 weeks ago
parent
commit
916ebe25ed
  1. 3
      vue-fastapi-backend/module_admin/entity/do/menu_do.py
  2. 1
      vue-fastapi-backend/module_admin/entity/vo/login_vo.py
  3. 2
      vue-fastapi-backend/module_admin/entity/vo/menu_vo.py
  4. 5
      vue-fastapi-backend/module_admin/service/login_service.py
  5. 2
      vue-fastapi-frontend/src/api/aichat/aichat.js
  6. 4
      vue-fastapi-frontend/src/utils/request.js
  7. 23
      vue-fastapi-frontend/src/views/aichat/MdRenderer.vue
  8. 53
      vue-fastapi-frontend/src/views/meta/metaInfo/index.vue
  9. 126
      vue-fastapi-frontend/src/views/system/menu/index.vue

3
vue-fastapi-backend/module_admin/entity/do/menu_do.py

@ -1,6 +1,7 @@
from datetime import datetime
from sqlalchemy import Column, DateTime, Integer, String
from config.database import Base
from sqlalchemy.dialects.mysql import LONGTEXT
class SysMenu(Base):
@ -30,3 +31,5 @@ class SysMenu(Base):
update_by = Column(String(64), nullable=True, default='', comment='更新者')
update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间')
remark = Column(String(500), nullable=True, default='', comment='备注')
desc = Column(String(500), nullable=True, default='', comment='页面描述')
link_params = Column(LONGTEXT, nullable=True, default='', comment='跳转参数')

1
vue-fastapi-backend/module_admin/entity/vo/login_vo.py

@ -63,6 +63,7 @@ class MenuTreeModel(MenuModel):
class MetaModel(BaseModel):
model_config = ConfigDict(alias_generator=to_camel)
id: Optional[int] = Field(default=None, description='菜单ID')
title: Optional[str] = Field(default=None, description='设置路由在侧边栏和面包屑中展示的名字')
icon: Optional[str] = Field(default=None, description='设置路由的图标')
no_cache: Optional[bool] = Field(default=None, description='设置为true,则不会被 <keep-alive>缓存')

2
vue-fastapi-backend/module_admin/entity/vo/menu_vo.py

@ -33,6 +33,8 @@ class MenuModel(BaseModel):
update_by: Optional[str] = Field(default=None, description='更新者')
update_time: Optional[datetime] = Field(default=None, description='更新时间')
remark: Optional[str] = Field(default=None, description='备注')
desc: Optional[str] = Field(default=None, description='页面描述')
link_params: Optional[str] = Field(default=None, description='跳转参数')
@NotBlank(field_name='menu_name', message='菜单名称不能为空')
@Size(field_name='menu_name', min_length=0, max_length=50, message='菜单名称长度不能超过50个字符')

5
vue-fastapi-backend/module_admin/service/login_service.py

@ -319,6 +319,7 @@ class LoginService:
component=RouterUtil.get_component(permission),
query=permission.query,
meta=MetaModel(
id=permission.menu_id,
title=permission.menu_name,
icon=permission.icon,
noCache=True if permission.is_cache == 1 else False,
@ -338,6 +339,7 @@ class LoginService:
component=permission.component,
name=RouterUtil.get_route_name(permission.route_name, permission.path),
meta=MetaModel(
id=permission.menu_id,
title=permission.menu_name,
icon=permission.icon,
noCache=True if permission.is_cache == 1 else False,
@ -348,7 +350,7 @@ class LoginService:
children_list.append(children)
router.children = children_list
elif permission.parent_id == 0 and RouterUtil.is_inner_link(permission):
router.meta = MetaModel(title=permission.menu_name, icon=permission.icon)
router.meta = MetaModel(id=permission.menu_id, title=permission.menu_name, icon=permission.icon)
router.path = '/'
children_list: List[RouterModel] = []
router_path = RouterUtil.inner_link_replace_each(permission.path)
@ -357,6 +359,7 @@ class LoginService:
component=MenuConstant.INNER_LINK,
name=RouterUtil.get_route_name(permission.route_name, permission.path),
meta=MetaModel(
id=permission.menu_id,
title=permission.menu_name,
icon=permission.icon,
link=permission.path if RouterUtil.is_http(permission.path) else None,

2
vue-fastapi-frontend/src/api/aichat/aichat.js

@ -50,7 +50,7 @@ export async function addChat(data) {
}
export async function postDataQuery(data) {
return request({
url: '/dataquery-api/chat/nl2sql_client_chat',
url: '/dataquery-api/datachat',
method: 'post',
data: data
})

4
vue-fastapi-frontend/src/utils/request.js

@ -17,11 +17,11 @@ const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
// baseURL: import.meta.env.VITE_APP_BASE_API,
// 超时
timeout: 100000
timeout: 180000
})
const rawAxios = axios.create({
baseURL: "/default-api",
timeout: 100000
timeout: 180000
});
rawAxios.interceptors.request.use(config => {

23
vue-fastapi-frontend/src/views/aichat/MdRenderer.vue

@ -20,6 +20,9 @@
<el-link type="primary" @click="downLoadFile(doc)" :underline="false">{{ doc.file_name }}</el-link>
</div>
</div>
<div v-if="item.type === 'router'" style="width: 100%;margin-top: 5px">
<el-link :underline="false" @click="jumpToPath(item.content)">{{'跳转到'+ item.content.menuName}}</el-link>
</div>
<div v-else style="width: 100%;margin-top: 5px">
<markdown :markdown-string="item.content"></markdown>
</div>
@ -34,7 +37,9 @@ import chatTable from './chatTable.vue'
import htmlCharts from './htmlCharts.vue'
import {Download, FullScreen} from "@element-plus/icons-vue";
import { ref, watch} from 'vue'
import { useRouter } from 'vue-router';
const { proxy } = getCurrentInstance();
const router = useRouter()
const props = defineProps({
source: Array,
is_large: Boolean,
@ -46,6 +51,24 @@ function fullscreenG6(data){
emit('fullscreenG6',data)
}
function jumpToPath(content){
let routes = router.getRoutes()
let obj = routes.find(route =>{return route.meta?.id === content.id;})
if (obj){
let path = '?'
let params = content.params
for (const key of params.keys()){
path += key+"="+params[key] + "&"
}
path = path.slice(0, -1);
path = obj.path + path
router.push(path)
}else {
proxy.$modal.msgWarning("该页面未授权,无法访问");
}
}
function downLoadFile(doc){
let data = {file:doc.file_name,bucket: doc.bucket,sessionId: doc.session_id}
proxy.download("/default-api/aichat/file/download", {

53
vue-fastapi-frontend/src/views/meta/metaInfo/index.vue

@ -847,7 +847,7 @@
import {getToken} from "@/utils/auth.js";
import {getDirectoryTree} from "@/api/metadataConfig/directory.js";
import {EditPen} from "@element-plus/icons-vue";
import { useRoute} from 'vue-router';
const data = reactive({
queryParams:{
ssysId:'',
@ -873,6 +873,8 @@
tags:[]
}
})
const route = useRoute();
// const router = useRouter()
const { queryParams, currentMetaData } = toRefs(data);
const loading = ref(true);
const drawer = ref(false);
@ -1505,7 +1507,7 @@
}
function handleQuery(){
queryParams.value.pageNum = 1;
getList()
return getList()
}
function resetQuery(){
queryParams.value ={
@ -1552,7 +1554,7 @@
}
}
function getList(){
getMetaDataList(queryParams.value).then(res=>{
return getMetaDataList(queryParams.value).then(res=>{
dataList.value = res.data.rows
let dbList = databaseList.value[0].children
if (dataList.value.length>0){
@ -1768,8 +1770,51 @@
}
onMounted(async () => {
await getDatabaseList()
handleQuery()
//
// const allRoutes = router.getRoutes()
// console.log(allRoutes)
if(route.query){
if (route.query.ssysId){
queryParams.value.ssysId = route.query.ssysId
}
if (route.query.mdlName){
queryParams.value.mdlName = route.query.mdlName
}
if (route.query.tabName){
queryParams.value.tabName = route.query.tabName
}
handleQuery().then(()=>{
console.log(dataList.value.length)
if (dataList.value.length === 1){
showColumnDialog(dataList.value[0])
}
})
}else{
await handleQuery()
}
})
watch(
() => route.query,
(newId) => {
console.log(route.query)
if (route.query.ssysId){
queryParams.value.ssysId = route.query.ssysId
}
if (route.query.mdlName){
queryParams.value.mdlName = route.query.mdlName
}
if (route.query.tabName){
queryParams.value.tabName = route.query.tabName
}
handleQuery().then(()=>{
if (dataList.value.length === 1){
showColumnDialog(dataList.value[0])
}
})
}
);
</script>

126
vue-fastapi-frontend/src/views/system/menu/index.vue

@ -64,6 +64,21 @@
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="desc" label="页面描述" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="linkParams" label="跳转参数" :show-overflow-tooltip="true" :tooltip-formatter="({ row }) => row.linkParams.map(tag=>tag.paramCnName).join(', ')">
<template #default="scope">
<template v-if="scope.row.linkParams && scope.row.linkParams.length>0">
<el-tag
v-for="tag in JSON.parse(scope.row.linkParams)"
:key="tag.paramEnName"
class="tag-item"
type="primary"
>
{{ tag.paramCnName }}
</el-tag>
</template>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
@ -276,6 +291,36 @@
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item>
<el-input type="textarea" v-model="form.desc" placeholder="请输入页面描述" />
<template #label>
<span>
<el-tooltip content='页面描述' placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
页面描述
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item label="跳转参数">
<el-tag
style="margin: 5px "
v-for="(tag,index) in form.linkParams"
closable
:key="tag.paramEnName"
class="tag-item"
type="primary"
@click="openLinkParamsDialog(tag, index)"
@close="handleClose(tag,index)"
>
{{ tag.paramCnName }}
</el-tag>
<el-button icon="Plus" type="primary" text @click="openLinkParamsDialog"></el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
@ -285,6 +330,28 @@
</div>
</template>
</el-dialog>
<el-dialog title="跳转参数配置" v-model="linkParamsDialog" width="480px" append-to-body>
<el-form :model="linkParam" label-width="100px">
<el-form-item label="英文名称" prop="paramEnName">
<el-input v-model="linkParam.paramEnName" placeholder="请输入英文名称" />
</el-form-item>
<el-form-item label="中文名称" prop="paramCnName">
<el-input v-model="linkParam.paramCnName" placeholder="请输入中文名称" />
</el-form-item>
<el-form-item label="取值类型" prop="paramType">
<el-input v-model="linkParam.paramType" placeholder="请输入取值类型" />
</el-form-item>
<el-form-item label="参数描述" prop="type">
<el-input type="textarea" v-model="linkParam.desc" placeholder="请输入参数描述" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="saveLinkParam"> </el-button>
<el-button @click="linkParamsDialog = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@ -305,9 +372,11 @@ const menuOptions = ref([]);
const isExpandAll = ref(false);
const refreshTable = ref(true);
const iconSelectRef = ref(null);
const linkParamsDialog = ref(null);
const data = reactive({
form: {},
linkParam:{},
queryParams: {
menuName: undefined,
visible: undefined
@ -319,8 +388,47 @@ const data = reactive({
},
});
const { queryParams, form, rules } = toRefs(data);
const { queryParams, form, rules, linkParam } = toRefs(data);
function openLinkParamsDialog(tag,index){
linkParam.value = {
tagIndex : -1,
paramEnName: '',
paramCnName:'',
paramType: '',
desc:''
}
if (tag){
linkParam.value = {
tagIndex : index,
paramEnName: tag.paramEnName,
paramCnName: tag.paramCnName,
paramType: tag.paramType,
desc: tag.desc
}
}
linkParamsDialog.value = true
}
function saveLinkParam(){
let obj = {
paramEnName: linkParam.value.paramEnName,
paramCnName:linkParam.value.paramCnName,
paramType: linkParam.value.paramType,
desc: linkParam.value.desc}
if (linkParam.value.tagIndex === -1){
if (!form.value.linkParams){
form.value.linkParams = []
}
form.value.linkParams.push(obj)
}else{
form.value.linkParams[linkParam.value.tagIndex] = obj
}
linkParamsDialog.value = false
}
function handleClose(tag,index){
form.value.linkParams.splice(index,1)
}
/** 查询菜单列表 */
function getList() {
loading.value = true;
@ -356,7 +464,9 @@ function reset() {
isFrame: 1,
isCache: 0,
visible: "0",
status: "0"
status: "0",
desc:'',
linkParams: undefined
};
proxy.resetForm("menuRef");
}
@ -402,7 +512,11 @@ async function handleUpdate(row) {
reset();
await getTreeselect();
getMenu(row.menuId).then(response => {
form.value = response.data;
let obj = response.data;
if (obj.linkParams && obj.linkParams.length > 0){
obj.linkParams = JSON.parse(obj.linkParams)
}
form.value = obj
open.value = true;
title.value = "修改菜单";
});
@ -411,14 +525,16 @@ async function handleUpdate(row) {
function submitForm() {
proxy.$refs["menuRef"].validate(valid => {
if (valid) {
let obj = JSON.parse(JSON.stringify(form.value))
obj.linkParams = JSON.stringify(obj.linkParams)
if (form.value.menuId != undefined) {
updateMenu(form.value).then(response => {
updateMenu(obj).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addMenu(form.value).then(response => {
addMenu(obj).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();

Loading…
Cancel
Save