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 datetime import datetime
from sqlalchemy import Column, DateTime, Integer, String from sqlalchemy import Column, DateTime, Integer, String
from config.database import Base from config.database import Base
from sqlalchemy.dialects.mysql import LONGTEXT
class SysMenu(Base): class SysMenu(Base):
@ -30,3 +31,5 @@ class SysMenu(Base):
update_by = Column(String(64), nullable=True, default='', comment='更新者') update_by = Column(String(64), nullable=True, default='', comment='更新者')
update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间')
remark = Column(String(500), nullable=True, default='', 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): class MetaModel(BaseModel):
model_config = ConfigDict(alias_generator=to_camel) model_config = ConfigDict(alias_generator=to_camel)
id: Optional[int] = Field(default=None, description='菜单ID')
title: Optional[str] = Field(default=None, description='设置路由在侧边栏和面包屑中展示的名字') title: Optional[str] = Field(default=None, description='设置路由在侧边栏和面包屑中展示的名字')
icon: Optional[str] = Field(default=None, description='设置路由的图标') icon: Optional[str] = Field(default=None, description='设置路由的图标')
no_cache: Optional[bool] = Field(default=None, description='设置为true,则不会被 <keep-alive>缓存') 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_by: Optional[str] = Field(default=None, description='更新者')
update_time: Optional[datetime] = Field(default=None, description='更新时间') update_time: Optional[datetime] = Field(default=None, description='更新时间')
remark: Optional[str] = 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='菜单名称不能为空') @NotBlank(field_name='menu_name', message='菜单名称不能为空')
@Size(field_name='menu_name', min_length=0, max_length=50, message='菜单名称长度不能超过50个字符') @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), component=RouterUtil.get_component(permission),
query=permission.query, query=permission.query,
meta=MetaModel( meta=MetaModel(
id=permission.menu_id,
title=permission.menu_name, title=permission.menu_name,
icon=permission.icon, icon=permission.icon,
noCache=True if permission.is_cache == 1 else False, noCache=True if permission.is_cache == 1 else False,
@ -338,6 +339,7 @@ class LoginService:
component=permission.component, component=permission.component,
name=RouterUtil.get_route_name(permission.route_name, permission.path), name=RouterUtil.get_route_name(permission.route_name, permission.path),
meta=MetaModel( meta=MetaModel(
id=permission.menu_id,
title=permission.menu_name, title=permission.menu_name,
icon=permission.icon, icon=permission.icon,
noCache=True if permission.is_cache == 1 else False, noCache=True if permission.is_cache == 1 else False,
@ -348,7 +350,7 @@ class LoginService:
children_list.append(children) children_list.append(children)
router.children = children_list router.children = children_list
elif permission.parent_id == 0 and RouterUtil.is_inner_link(permission): 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 = '/' router.path = '/'
children_list: List[RouterModel] = [] children_list: List[RouterModel] = []
router_path = RouterUtil.inner_link_replace_each(permission.path) router_path = RouterUtil.inner_link_replace_each(permission.path)
@ -357,6 +359,7 @@ class LoginService:
component=MenuConstant.INNER_LINK, component=MenuConstant.INNER_LINK,
name=RouterUtil.get_route_name(permission.route_name, permission.path), name=RouterUtil.get_route_name(permission.route_name, permission.path),
meta=MetaModel( meta=MetaModel(
id=permission.menu_id,
title=permission.menu_name, title=permission.menu_name,
icon=permission.icon, icon=permission.icon,
link=permission.path if RouterUtil.is_http(permission.path) else None, 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) { export async function postDataQuery(data) {
return request({ return request({
url: '/dataquery-api/chat/nl2sql_client_chat', url: '/dataquery-api/datachat',
method: 'post', method: 'post',
data: data data: data
}) })

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

@ -17,11 +17,11 @@ const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分 // axios中请求配置有baseURL选项,表示请求URL公共部分
// baseURL: import.meta.env.VITE_APP_BASE_API, // baseURL: import.meta.env.VITE_APP_BASE_API,
// 超时 // 超时
timeout: 100000 timeout: 180000
}) })
const rawAxios = axios.create({ const rawAxios = axios.create({
baseURL: "/default-api", baseURL: "/default-api",
timeout: 100000 timeout: 180000
}); });
rawAxios.interceptors.request.use(config => { 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> <el-link type="primary" @click="downLoadFile(doc)" :underline="false">{{ doc.file_name }}</el-link>
</div> </div>
</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"> <div v-else style="width: 100%;margin-top: 5px">
<markdown :markdown-string="item.content"></markdown> <markdown :markdown-string="item.content"></markdown>
</div> </div>
@ -34,7 +37,9 @@ import chatTable from './chatTable.vue'
import htmlCharts from './htmlCharts.vue' import htmlCharts from './htmlCharts.vue'
import {Download, FullScreen} from "@element-plus/icons-vue"; import {Download, FullScreen} from "@element-plus/icons-vue";
import { ref, watch} from 'vue' import { ref, watch} from 'vue'
import { useRouter } from 'vue-router';
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const router = useRouter()
const props = defineProps({ const props = defineProps({
source: Array, source: Array,
is_large: Boolean, is_large: Boolean,
@ -46,6 +51,24 @@ function fullscreenG6(data){
emit('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){ function downLoadFile(doc){
let data = {file:doc.file_name,bucket: doc.bucket,sessionId: doc.session_id} let data = {file:doc.file_name,bucket: doc.bucket,sessionId: doc.session_id}
proxy.download("/default-api/aichat/file/download", { 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 {getToken} from "@/utils/auth.js";
import {getDirectoryTree} from "@/api/metadataConfig/directory.js"; import {getDirectoryTree} from "@/api/metadataConfig/directory.js";
import {EditPen} from "@element-plus/icons-vue"; import {EditPen} from "@element-plus/icons-vue";
import { useRoute} from 'vue-router';
const data = reactive({ const data = reactive({
queryParams:{ queryParams:{
ssysId:'', ssysId:'',
@ -873,6 +873,8 @@
tags:[] tags:[]
} }
}) })
const route = useRoute();
// const router = useRouter()
const { queryParams, currentMetaData } = toRefs(data); const { queryParams, currentMetaData } = toRefs(data);
const loading = ref(true); const loading = ref(true);
const drawer = ref(false); const drawer = ref(false);
@ -1505,7 +1507,7 @@
} }
function handleQuery(){ function handleQuery(){
queryParams.value.pageNum = 1; queryParams.value.pageNum = 1;
getList() return getList()
} }
function resetQuery(){ function resetQuery(){
queryParams.value ={ queryParams.value ={
@ -1552,7 +1554,7 @@
} }
} }
function getList(){ function getList(){
getMetaDataList(queryParams.value).then(res=>{ return getMetaDataList(queryParams.value).then(res=>{
dataList.value = res.data.rows dataList.value = res.data.rows
let dbList = databaseList.value[0].children let dbList = databaseList.value[0].children
if (dataList.value.length>0){ if (dataList.value.length>0){
@ -1768,8 +1770,51 @@
} }
onMounted(async () => { onMounted(async () => {
await getDatabaseList() 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> </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="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></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="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"> <el-table-column prop="status" label="状态" width="80">
<template #default="scope"> <template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" /> <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
@ -276,6 +291,36 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </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-row>
</el-form> </el-form>
<template #footer> <template #footer>
@ -285,6 +330,28 @@
</div> </div>
</template> </template>
</el-dialog> </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> </div>
</template> </template>
@ -305,9 +372,11 @@ const menuOptions = ref([]);
const isExpandAll = ref(false); const isExpandAll = ref(false);
const refreshTable = ref(true); const refreshTable = ref(true);
const iconSelectRef = ref(null); const iconSelectRef = ref(null);
const linkParamsDialog = ref(null);
const data = reactive({ const data = reactive({
form: {}, form: {},
linkParam:{},
queryParams: { queryParams: {
menuName: undefined, menuName: undefined,
visible: 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() { function getList() {
loading.value = true; loading.value = true;
@ -356,7 +464,9 @@ function reset() {
isFrame: 1, isFrame: 1,
isCache: 0, isCache: 0,
visible: "0", visible: "0",
status: "0" status: "0",
desc:'',
linkParams: undefined
}; };
proxy.resetForm("menuRef"); proxy.resetForm("menuRef");
} }
@ -402,7 +512,11 @@ async function handleUpdate(row) {
reset(); reset();
await getTreeselect(); await getTreeselect();
getMenu(row.menuId).then(response => { 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; open.value = true;
title.value = "修改菜单"; title.value = "修改菜单";
}); });
@ -411,14 +525,16 @@ async function handleUpdate(row) {
function submitForm() { function submitForm() {
proxy.$refs["menuRef"].validate(valid => { proxy.$refs["menuRef"].validate(valid => {
if (valid) { if (valid) {
let obj = JSON.parse(JSON.stringify(form.value))
obj.linkParams = JSON.stringify(obj.linkParams)
if (form.value.menuId != undefined) { if (form.value.menuId != undefined) {
updateMenu(form.value).then(response => { updateMenu(obj).then(response => {
proxy.$modal.msgSuccess("修改成功"); proxy.$modal.msgSuccess("修改成功");
open.value = false; open.value = false;
getList(); getList();
}); });
} else { } else {
addMenu(form.value).then(response => { addMenu(obj).then(response => {
proxy.$modal.msgSuccess("新增成功"); proxy.$modal.msgSuccess("新增成功");
open.value = false; open.value = false;
getList(); getList();

Loading…
Cancel
Save