api路径修复

This commit is contained in:
chenxing
2026-08-19 12:01:26 +08:00
parent eb0ab76c83
commit 35529fc671
7 changed files with 123 additions and 890 deletions
+11 -11
View File
@@ -28,10 +28,10 @@ export default {
'SysUser.add': ['POST', '/api/sysuser/Add'],
'SysGroup.sortChildren': ['POST', '/api/sysgroup/SortChildren'],
'SysGroup.move': ['POST', '/api/sysgroup/Move'],
'SysGroup.edit_1': ['POST', '/api/sysgroup/Edit/{id}'],
'SysGroup.delete_': ['POST', '/api/sysgroup/Delete/{id}'],
'SysGroup.sysGroupEdit': ['POST', '/api/sysgroup/Edit/{id}'],
'SysGroup.sysGroupRemove': ['POST', '/api/sysgroup/Delete/{id}'],
'SysGroup.batchAdd': ['POST', '/api/sysgroup/BatchAdd'],
'SysGroup.add_1': ['POST', '/api/sysgroup/Add'],
'SysGroup.sysGroupAdd': ['POST', '/api/sysgroup/Add'],
'PushSubscription.test': ['POST', '/api/push/Test'],
'PushSubscription.retry': ['POST', '/api/push/Retry/{id}'],
'Identity.switchIdentity': ['POST', '/api/identity/switch'],
@@ -62,19 +62,19 @@ export default {
'AppSettings.addModule': ['POST', '/api/app/AddModule'],
'AppSettings.addApp': ['POST', '/api/app/AddApp'],
'User.moveToGroup': ['POST', '/oapi/user/moveToGroup'],
'User.edit_2': ['POST', '/oapi/user/edit/{id}'],
'User.delete_1': ['POST', '/oapi/user/delete/{id}/{groupId}'],
'User.edit_1': ['POST', '/oapi/user/edit/{id}'],
'User.delete_': ['POST', '/oapi/user/delete/{id}/{groupId}'],
'User.batchAdd_1': ['POST', '/oapi/user/batchAdd'],
'User.add_2': ['POST', '/oapi/user/add'],
'Group.edit_3': ['POST', '/oapi/group/edit/{id}'],
'Group.delete_2': ['POST', '/oapi/group/delete/{id}'],
'User.add_1': ['POST', '/oapi/user/add'],
'Group.edit_2': ['POST', '/oapi/group/edit/{id}'],
'Group.delete_1': ['POST', '/oapi/group/delete/{id}'],
'Group.batchAdd_2': ['POST', '/oapi/group/batchAdd'],
'Group.add_3': ['POST', '/oapi/group/add'],
'Group.add_2': ['POST', '/oapi/group/add'],
'SysUser.list': ['GET', '/api/sysuser/List'],
'SysUser.getUserGroups': ['GET', '/api/sysuser/Groups/{userId}'],
'SysUser.export_': ['GET', '/api/sysuser/Export'],
'SysUser.downloadTemplate': ['GET', '/api/sysuser/DownloadTemplate'],
'SysGroup.list_1': ['GET', '/api/sysgroup/List'],
'SysGroup.sysGroupList': ['GET', '/api/sysgroup/List'],
'SysGroup.getTree': ['GET', '/api/sysgroup/GetTree'],
'SysGroup.getSchoolTree': ['GET', '/api/sysgroup/GetSchoolTree'],
'PushSubscription.recordList': ['GET', '/api/push/RecordList'],
@@ -112,6 +112,6 @@ export default {
'User.byId': ['GET', '/oapi/user/byId'],
'SignKeyInternal.signKey': ['GET', '/oapi/internal/sign-key/{appId}'],
'Group.tree': ['GET', '/oapi/group/tree'],
'Group.list_2': ['GET', '/oapi/group/list'],
'Group.list_1': ['GET', '/oapi/group/list'],
'Group.byId_1': ['GET', '/oapi/group/byId']
};
+109 -109
View File
@@ -481,33 +481,47 @@ export interface RedirectView {
attributeNames?: object;
majorVersion?: number;
contextPath?: string;
minorVersion?: number;
initParameterNames?: object;
sessionTimeout?: number;
/**
* @deprecated
*/
servletNames?: object;
minorVersion?: number;
initParameterNames?: object;
sessionTimeout?: number;
serverInfo?: string;
/**
* @deprecated
*/
servlets?: object;
requestCharacterEncoding?: string;
jspConfigDescriptor?: {
taglibs?: Array<{
taglibLocation?: string;
taglibURI?: string;
}>;
jspPropertyGroups?: Array<{
buffer?: string;
defaultContentType?: string;
urlPatterns?: string[];
includePreludes?: string[];
trimDirectiveWhitespaces?: string;
scriptingInvalid?: string;
errorOnUndeclaredNamespace?: string;
includeCodas?: string[];
elIgnored?: string;
pageEncoding?: string;
isXml?: string;
deferredSyntaxAllowedAsLiteral?: string;
}>;
};
effectiveMajorVersion?: number;
servletContextName?: string;
virtualServerName?: string;
filterRegistrations?: Record<
string,
{
urlPatternMappings?: string[];
servletNameMappings?: string[];
urlPatternMappings?: string[];
name?: string;
className?: string;
initParameters?: Record<string, string>;
}
>;
servletContextName?: string;
sessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[];
effectiveMinorVersion?: number;
defaultSessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[];
servletRegistrations?: Record<
string,
{
@@ -518,8 +532,11 @@ export interface RedirectView {
initParameters?: Record<string, string>;
}
>;
effectiveMajorVersion?: number;
virtualServerName?: string;
effectiveMinorVersion?: number;
sessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[];
effectiveSessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[];
defaultSessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[];
responseCharacterEncoding?: string;
sessionCookieConfig?: {
name?: string;
path?: string;
@@ -529,28 +546,11 @@ export interface RedirectView {
maxAge?: number;
httpOnly?: boolean;
};
jspConfigDescriptor?: {
taglibs?: Array<{
taglibURI?: string;
taglibLocation?: string;
}>;
jspPropertyGroups?: Array<{
buffer?: string;
urlPatterns?: string[];
defaultContentType?: string;
elIgnored?: string;
pageEncoding?: string;
isXml?: string;
includeCodas?: string[];
trimDirectiveWhitespaces?: string;
includePreludes?: string[];
scriptingInvalid?: string;
errorOnUndeclaredNamespace?: string;
deferredSyntaxAllowedAsLiteral?: string;
}>;
};
responseCharacterEncoding?: string;
effectiveSessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[];
serverInfo?: string;
/**
* @deprecated
*/
servlets?: object;
};
contentType?: string;
requestContextAttribute?: string;
@@ -1412,7 +1412,7 @@ declare global {
* type Response = null
* ```
*/
edit_1<
sysGroupEdit<
Config extends Alova2MethodConfig<null> & {
pathParams: {
id: number;
@@ -1421,7 +1421,7 @@ declare global {
}
>(
config: Config
): Alova2Method<null, 'SysGroup.edit_1', Config>;
): Alova2Method<null, 'SysGroup.sysGroupEdit', Config>;
/**
* ---
*
@@ -1445,7 +1445,7 @@ declare global {
* type Response = null
* ```
*/
delete_<
sysGroupRemove<
Config extends Alova2MethodConfig<null> & {
pathParams: {
id: number;
@@ -1453,7 +1453,7 @@ declare global {
}
>(
config: Config
): Alova2Method<null, 'SysGroup.delete_', Config>;
): Alova2Method<null, 'SysGroup.sysGroupRemove', Config>;
/**
* ---
*
@@ -1517,13 +1517,13 @@ declare global {
* type Response = null
* ```
*/
add_1<
sysGroupAdd<
Config extends Alova2MethodConfig<null> & {
data: SysGroupRequest;
}
>(
config: Config
): Alova2Method<null, 'SysGroup.add_1', Config>;
): Alova2Method<null, 'SysGroup.sysGroupAdd', Config>;
/**
* ---
*
@@ -1559,7 +1559,7 @@ declare global {
* }>
* ```
*/
list_1<
sysGroupList<
Config extends Alova2MethodConfig<SysGroupVo[]> & {
params: {
query: SysGroupQuery;
@@ -1567,7 +1567,7 @@ declare global {
}
>(
config: Config
): Alova2Method<SysGroupVo[], 'SysGroup.list_1', Config>;
): Alova2Method<SysGroupVo[], 'SysGroup.sysGroupList', Config>;
/**
* ---
*
@@ -2550,37 +2550,59 @@ declare global {
* attributeNames?: object
* majorVersion?: number
* contextPath?: string
* // [deprecated]
* servletNames?: object
* minorVersion?: number
* initParameterNames?: object
* sessionTimeout?: number
* serverInfo?: string
* // [deprecated]
* servlets?: object
* servletNames?: object
* requestCharacterEncoding?: string
* jspConfigDescriptor?: {
* // [items] start
* // [items] end
* taglibs?: Array<{
* taglibLocation?: string
* taglibURI?: string
* }>
* // [items] start
* // [items] end
* jspPropertyGroups?: Array<{
* buffer?: string
* defaultContentType?: string
* // [items] start
* // [items] end
* urlPatterns?: string[]
* // [items] start
* // [items] end
* includePreludes?: string[]
* trimDirectiveWhitespaces?: string
* scriptingInvalid?: string
* errorOnUndeclaredNamespace?: string
* // [items] start
* // [items] end
* includeCodas?: string[]
* elIgnored?: string
* pageEncoding?: string
* isXml?: string
* deferredSyntaxAllowedAsLiteral?: string
* }>
* }
* effectiveMajorVersion?: number
* servletContextName?: string
* virtualServerName?: string
* filterRegistrations?: Record<
* string,
* {
* // [items] start
* // [items] end
* urlPatternMappings?: string[]
* servletNameMappings?: string[]
* // [items] start
* // [items] end
* servletNameMappings?: string[]
* urlPatternMappings?: string[]
* name?: string
* className?: string
* initParameters?: Record<string, string>
* }
* >
* servletContextName?: string
* // [items] start
* // [items] end
* sessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[]
* effectiveMinorVersion?: number
* // [items] start
* // [items] end
* defaultSessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[]
* servletRegistrations?: Record<
* string,
* {
@@ -2593,8 +2615,17 @@ declare global {
* initParameters?: Record<string, string>
* }
* >
* effectiveMajorVersion?: number
* virtualServerName?: string
* effectiveMinorVersion?: number
* // [items] start
* // [items] end
* sessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[]
* // [items] start
* // [items] end
* effectiveSessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[]
* // [items] start
* // [items] end
* defaultSessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[]
* responseCharacterEncoding?: string
* sessionCookieConfig?: {
* name?: string
* path?: string
@@ -2604,40 +2635,9 @@ declare global {
* maxAge?: number
* httpOnly?: boolean
* }
* jspConfigDescriptor?: {
* // [items] start
* // [items] end
* taglibs?: Array<{
* taglibURI?: string
* taglibLocation?: string
* }>
* // [items] start
* // [items] end
* jspPropertyGroups?: Array<{
* buffer?: string
* // [items] start
* // [items] end
* urlPatterns?: string[]
* defaultContentType?: string
* elIgnored?: string
* pageEncoding?: string
* isXml?: string
* // [items] start
* // [items] end
* includeCodas?: string[]
* trimDirectiveWhitespaces?: string
* // [items] start
* // [items] end
* includePreludes?: string[]
* scriptingInvalid?: string
* errorOnUndeclaredNamespace?: string
* deferredSyntaxAllowedAsLiteral?: string
* }>
* }
* responseCharacterEncoding?: string
* // [items] start
* // [items] end
* effectiveSessionTrackingModes?: ('COOKIE' | 'URL' | 'SSL')[]
* serverInfo?: string
* // [deprecated]
* servlets?: object
* }
* contentType?: string
* requestContextAttribute?: string
@@ -4196,7 +4196,7 @@ declare global {
* }
* ```
*/
edit_2<
edit_1<
Config extends Alova2MethodConfig<BoaUser> & {
pathParams: {
id: number;
@@ -4205,7 +4205,7 @@ declare global {
}
>(
config: Config
): Alova2Method<BoaUser, 'User.edit_2', Config>;
): Alova2Method<BoaUser, 'User.edit_1', Config>;
/**
* ---
*
@@ -4230,7 +4230,7 @@ declare global {
* type Response = null
* ```
*/
delete_1<
delete_<
Config extends Alova2MethodConfig<null> & {
pathParams: {
id: number;
@@ -4239,7 +4239,7 @@ declare global {
}
>(
config: Config
): Alova2Method<null, 'User.delete_1', Config>;
): Alova2Method<null, 'User.delete_', Config>;
/**
* ---
*
@@ -4473,13 +4473,13 @@ declare global {
* }
* ```
*/
add_2<
add_1<
Config extends Alova2MethodConfig<BoaUser> & {
data: SysUserRequest;
}
>(
config: Config
): Alova2Method<BoaUser, 'User.add_2', Config>;
): Alova2Method<BoaUser, 'User.add_1', Config>;
/**
* ---
*
@@ -4889,7 +4889,7 @@ declare global {
* }
* ```
*/
edit_3<
edit_2<
Config extends Alova2MethodConfig<BoaGroup> & {
pathParams: {
id: number;
@@ -4898,7 +4898,7 @@ declare global {
}
>(
config: Config
): Alova2Method<BoaGroup, 'Group.edit_3', Config>;
): Alova2Method<BoaGroup, 'Group.edit_2', Config>;
/**
* ---
*
@@ -4922,7 +4922,7 @@ declare global {
* type Response = null
* ```
*/
delete_2<
delete_1<
Config extends Alova2MethodConfig<null> & {
pathParams: {
id: number;
@@ -4930,7 +4930,7 @@ declare global {
}
>(
config: Config
): Alova2Method<null, 'Group.delete_2', Config>;
): Alova2Method<null, 'Group.delete_1', Config>;
/**
* ---
*
@@ -5014,13 +5014,13 @@ declare global {
* }
* ```
*/
add_3<
add_2<
Config extends Alova2MethodConfig<BoaGroup> & {
data: SysGroupRequest;
}
>(
config: Config
): Alova2Method<BoaGroup, 'Group.add_3', Config>;
): Alova2Method<BoaGroup, 'Group.add_2', Config>;
/**
* ---
*
@@ -5080,7 +5080,7 @@ declare global {
* }>
* ```
*/
list_2<
list_1<
Config extends Alova2MethodConfig<BoaGroup[]> & {
params: {
ids: string;
@@ -5089,7 +5089,7 @@ declare global {
}
>(
config: Config
): Alova2Method<BoaGroup[], 'Group.list_2', Config>;
): Alova2Method<BoaGroup[], 'Group.list_1', Config>;
/**
* ---
*
-158
View File
@@ -1,158 +0,0 @@
<template>
<Modal v-model="show" :mask-closable="false" width="600" :title="titleComp" @on-visible-change="visibleChange">
<Form ref="formRef" class="mr-15" :model="form" :rules="rules" :label-width="100">
<FormItem :label="bookInfo.name + '名称:'" prop="name">
<Input v-model="form.name" :placeholder="`请输入${bookInfo.name}名称`" />
</FormItem>
<Row class="mb-20">
<Col span="12">
<FormItem label="年级" prop="grade">
<Select v-model="form.grade" transfer clearable placeholder="选择年级">
<Option v-for="item in dictData.grade" :value="item.id" :key="item.id">{{ item.name }}
</Option>
</Select>
</FormItem>
</Col>
<Col span="12">
<FormItem label="学期:" prop="semester">
<Select v-model="form.semester" transfer placeholder="选择学期">
<Option :value="0">上学期</Option>
<Option :value="1">下学期</Option>
</Select>
</FormItem>
</Col>
</Row>
<Row class="mb-20">
<Col span="12">
<FormItem label="学科:" prop="subject">
<Select v-model="form.subject" transfer clearable placeholder="选择科目">
<Option v-for="item in dictData.subject" :value="item.code" :key="item.code">{{ item.name }}
</Option>
</Select>
</FormItem>
</Col>
<Col span="12">
<FormItem label="出版社:" prop="press">
<Input v-model="form.press" placeholder="输入出版社" />
</FormItem>
</Col>
</Row>
<Row class="mb-20">
<Col span="12">
<FormItem label="出版年份:" prop="outTime">
<DatePicker v-model="form.outTime" type="year" placeholder="请选择年份" format="yyyy" transfer
:editable="false" :clearable="true" @on-change="v => form.outTime = v"></DatePicker>
</FormItem>
</Col>
</Row>
</Form>
<template #footer>
<Button type="primary" :loading="loading" @click="handleSubmit">提交</Button>
<Button @click="handleClose">取消</Button>
</template>
</Modal>
</template>
<script setup lang="ts">
import { reactive, watch, computed, nextTick } from 'vue'
import { BooxType, BooxTypeDict } from '@/types/index'
import useBookInfo from '../useBookInfo'
const props = defineProps({
modelValue: Boolean,
id: { type: [String, Number], required: true },// 0 新增 / 其它 编辑
bookType: { type: Number, default: 1, required: true }//教材|教辅
})
const emit = defineEmits(['update:modelValue', 'success'])
const show = computed({
get: () => props.modelValue,
set: val => emit('update:modelValue', val)
})
const { data: dictData } = useRequest(Apis.Base.getSystemDict({
cacheFor: 1000 * 60 * 60
}), {
initialData: {
grade: [],
press: [],
subject: [],
}
});
const isAdd = computed(() => props.id == 0)
const formRef = ref()
const loading = ref(false)
const { bookInfo } = useBookInfo()
const rules = {
name: [{ required: true, message: '请输入名称' }],
subject: [{ required: true, message: '请选择学科' }],
grade: [{ required: true, message: '请选择年级' }],
press: [{ required: false, message: '请输入出版社' }],
semester: [{ required: true, message: '请选择学期' }],
outTime: [{ required: false, message: '请选择年份' }],
}
// 打开弹窗时拉取详情(编辑模式)
watch(() => props.modelValue, async val => {
if (!val) return
if (isAdd.value) {
// 新增重置空表单
nextTick(() => formRef.value?.resetFields())
Object.assign(form.value, { ...form.value, bookType: props.bookType })
} else {
const resp = await Apis.Knowledge.getTextbookById({ params: { id: props.id } })
Object.assign(form.value, resp)
}
})
const titleComp = computed(() => {
return (isAdd.value ? '新增' : '编辑') + bookInfo.value.name
})
function visibleChange(v: any) {
if (!v) setTimeout(() => {
formRef.value?.resetFields()
}, 100);
}
async function handleSubmit() {
let validate = await formRef.value.validate()
loading.value = true
try {
if (!validate) throw '请填写红色星号内容'
await sendForm()
handleClose()
emit('success')
} catch (error) {
Message.info(error)
}
finally {
loading.value = false
}
}
const {
form,
send: sendForm,
} = useForm((dto) => Apis.Knowledge.saveTextbook({ data: dto }), {
initialForm: {
id: null,
name: '',
subject: '',
grade: '',
press: '',
semester: '',
outTime: ''
},
resetAfterSubmiting: false
})
function handleClose() {
emit('update:modelValue', false)
}
</script>
-301
View File
@@ -1,301 +0,0 @@
<template>
<div class="main-wrapper">
<div class="main-container">
<div class="fix mb-12">
<Button type="primary" @click="curEditId = 0, eidtModelShow = true" class="fl">
添加{{ bookInfo.name }}
</Button>
<Button type="success" @click="uploadType = 2, uploadModelShow = true" class="fr ml-12">
导入{{ bookInfo.name }}和目录树
</Button>
<Button type="success" @click="uploadType = 1, uploadModelShow = true" class="fr ml-12">
导入{{ bookInfo.name }}
</Button>
</div>
<div class="search-wrap fix">
<Select class="search-wrap_sel" v-model="dataParams.subject" clearable placeholder="选择科目">
<Option v-for="item in dictData.subject" :value="item.code" :key="item.code">{{ item.name }}
</Option>
</Select>
<Select class="search-wrap_sel ml-12" v-model="dataParams.grade" clearable placeholder="选择年级">
<Option v-for="item in dictData.grade" :value="item.id" :key="item.id">{{ item.name }}
</Option>
</Select>
<Select class="search-wrap_sel ml-12" v-model="dataParams.press" clearable placeholder="选择出版社">
<Option v-for="item in pressList" :value="item.v" :key="item.k">{{ item.v }}
</Option>
</Select>
<Select class="search-wrap_sel ml-12" v-model="dataParams.semester" clearable placeholder="选择学期">
<Option :value="0">上学期</Option>
<Option :value="1">下学期</Option>
</Select>
<Input class="fr ml-12" v-model="dataParams.name" placeholder="输入关键字筛选" suffix="ios-search" clearable
style="width:200px" />
</div>
<TablePageAlova ref="tableRef" :dataApi="tableApi" :columns="columns" :dataParams="dataParams"
:tableHeight="tableHeight">
</TablePageAlova>
<Drawer width="400" :title="drawerTitle" :closable="false" v-model="showDrawer">
<MyTree :treeData="knowTreeData" :setting="treeSetting2" :autoClick="false" />
</Drawer>
</div>
<div class="modal-wrap">
<EditModel v-model="eidtModelShow" :id="curEditId" :bookType="bookInfo.type" @success="reloadTable" />
<Modal v-model="uploadModelShow" :mask-closable="false" width="600" :title="modalTitle">
<BschImport ref="importRef" :tempFileUrl="tempFileUrl" :uploadUrl="uploadUrl" :uploadData="uploadData"
@on-success="reloadTable" />
<template #footer>
<Button @click="uploadModelShow = false">关闭</Button>
</template>
</Modal>
<Modal v-model="knowledgeModelShow" :mask-closable="false" width="900" title="目录树管理">
<Knowledge :id="curKnowId" :name="curKnowName" v-if="knowledgeModelShow" />
<template #footer>
<Button @click="knowledgeModelShow = false">关闭</Button>
</template>
</Modal>
<!-- BschImport -->
</div>
</div>
</template>
<script lang="ts" setup>
import { } from "vue";
import TablePageAlova from '@/components/TablePageAlova.vue'
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
import Knowledge from './Knowledge.vue'
import { useDefaultStore } from "@/store";
import EditModel from './EditModel.vue'
import MyTree from '@/components/MyTree.vue'
import MyConfirm from "@/components/MyConfirm";
import BschImport from '@/components/BschImport.vue'
import useBookInfo from "../useBookInfo";
import { useRouter } from "vue-router";
import { OperatorEnum } from "@/types";
const store = useDefaultStore();
const { $conf, $bus, $utils } = useCurrentInstance();
const { bookInfo } = useBookInfo()
const eidtModelShow = ref(false);
const knowledgeModelShow = ref(false);
const uploadType = ref(0);
const uploadModelShow = ref(false);
const curEditId = ref(0)
const tableRef = useTemplateRef('tableRef')
const curKnowId = ref(0)
const curKnowName = ref('')
const router = useRouter();
const dataParams = ref({
pageSize: '',
pageIndex: '',
grade: null,
semester: null,
subject: null,
press: null,
name: null,
bookType: bookInfo.value.type,
})
const treeSetting2 = ref({
view: {
dblClickExpand: false,
showIcon: false,
},
edit: {
enable: true,
showRemoveBtn: false,
showRenameBtn: false,
drag: false,
},
check: {
enable: false,
},
callback: {},
})
const tableHeight = ref($utils.useTableHeight({ isOperat: true, isPage: true, isSearch: true }));
const { data: dictData } = useRequest(Apis.Base.getSystemDict({
cacheFor: 1000 * 60 * 60
}), {
initialData: {
grade: [],
textPress: [],
teachingPress: [],
subject: [],
}
});
const { data: knowTreeData, send: sendKnowledgTree } =
useRequest((textbookId: number) => Apis.Knowledge.getTreeByTextbookId({
params: { textbookId },
transform: (res: any) => {
let arr = res || [];
return arr.map((item: any) => {
item.open = true;
return item;
})
},
}), {
initialData: [],
immediate: false
});
const showDrawer = ref(false);
const drawerTitle = ref('');
const columns = ref([
{ type: 'index', title: '序号', width: 80 },
{ title: bookInfo.value.name + '名称', key: 'name' },
{ title: '年级', key: 'gradeName' },
{
title: '学期',
key: 'semester',
render: (h: any, params: any) => {
return h('span', params.row.semester == 0 ? '上学期' : '下学期');
}
},
{ title: '科目', key: 'subjectName' },
{ title: '出版社', key: 'press' },
{ title: '出版年份', key: 'outTime' },
// {
// title: '封面',
// key: 'coverImage',
// width: 120,
// render: (row: any, { row: r }: any) => {
// const src = r.coverImage || new URL('@/assets/image/default-bg1.png', import.meta.url).href
// return h('img', {
// src,
// style: {
// width: '20px',
// height: '30px',
// objectFit: 'cover',
// borderRadius: '4px'
// },
// alt: '封面'
// })
// }
// },
{
title: '操作',
width: 240,
align: 'center',
render: (h: any, params: any) => {
const disabled = params.row.disabled;
return [
$utils.operatingTextHandle(h, '目录树管理', '', () => {
// router.push({
// path: '/' + bookInfo.value.path + '/manage/knowledge',
// query: { id: params.row.id, name: params.row.name },
// });
curKnowId.value = params.row.id;
curKnowName.value = params.row.name;
knowledgeModelShow.value = true;
}, disabled),
$utils.operatingTextHandle(h, '查看', '', () => {
drawerTitle.value = params.row.name;
showDrawer.value = true;
setTimeout(() => {
sendKnowledgTree(params.row.id);
}, 100);
}),
$utils.operatingTextHandle(h, '编辑', '', () => {
curEditId.value = params.row.id;
eidtModelShow.value = true;
}, disabled),
$utils.operatingTextHandle(h, '删除', 'text-error', () => {
removeSave(params.row.id)
}, disabled),
];
}
}
])
const modalTitle = computed(() => {
return '导入' + bookInfo.value.name + (uploadType.value === 1 ? '' : '和知识树');
})
const tempFileUrl = computed(() => {
const method = uploadType.value == 1 ? 'getTextbookTemplate' : 'getTextbookKnowledgeTemplate';
let url = $conf.serviceHost + `/api/knowledge/${method}?bookType=` + bookInfo.value.type;
return url;
})
const uploadUrl = computed(() => {
const method = uploadType.value == 1 ? '/api/knowledge/importTextbook' : '/api/knowledge/importTextbookInfo';
return $conf.serviceHost + method;
})
const uploadData = computed(() => {
return { bookType: bookInfo.value.type };
})
const pressList = computed(() => {
return bookInfo.value.type == 1 ? dictData.value.textPress : dictData.value.teachingPress
})
const clean = (obj: Record<string, any>) =>
Object.fromEntries(
Object.entries(obj).filter(([, v]) => v != null && v !== '')
)
const tableApi = (params: { pageIndex: number; pageSize: number }) => {
return Apis.Knowledge.searchTextbooks({
params: clean({ ...dataParams.value, ...params }),
cacheFor: null,
})
}
onBeforeMount(() => {
$bus.emit('resetLayout', { identity: bookInfo.value.identity, modId: (bookInfo.value.baseModId + 4) });
});
/**
* removeSave
*/
async function removeSave(id: number) {
await MyConfirm({
msg: "确定删除该教材吗?",
info: "关联目录树也将会被删除,删除后不可恢复!",
async onOk() {
try {
await Apis.Knowledge.deleteTextbook({ params: { id } });
Message.success("操作成功!");
tableRef.value?.reloadData(OperatorEnum.del);
} catch (error) {
// 全局拦截器已弹窗,这里仅记录日志避免二次弹窗
console.warn(error);
}
},
});
}
function reloadTable() {
if (!curEditId.value) tableRef.value?.reloadData(OperatorEnum.add);
else tableRef.value?.reloadData(OperatorEnum.edit);
}
</script>
<style lang="scss" scoped></style>
-301
View File
@@ -1,301 +0,0 @@
<template>
<div class="main-wrapper" style="min-height: 400px;">
<div class="main-container">
<div class="search-wrap ">
<h5 class="title mt-4 fl">{{ title }}</h5>
<Button type="success" class="fr" @click="uploadModelShow = true">导入目录树</Button>
</div>
<Table row-key="id" :columns="columns" :loading="tableLoading" :indent-size="20" :data="tableDataComp">
<template #loading>
<div class="table-spin-load">加载中</div>
</template>
</Table>
</div>
<div class="modal-wrap">
<Modal v-model="editNodeModal.modal" :title="editNodeModal.title" width="450px" :mask-closable="false">
<Form ref="refFormData" :label-width="100" :model="editNodeModal" class="myform mb-20 mr-20">
<Form-Item label="节点名称:" prop="name"
:rules="{ required: true, message: '请输入节点名称', trigger: 'blur' }">
<Input ref="refNodeNameInput" maxlength="30" v-model="editNodeModal.name" />
</Form-Item>
</Form>
<template #footer>
<Button type="primary" :loading="editNodeModal.loading" @click="saveEditNode">确认</Button>
<Button :loading="editNodeModal.loading" @click="editNodeModal.modal = false">取消</Button>
</template>
</Modal>
<!-- 排序弹窗 -->
<Modal v-model="sortModal.modal" title="子节点排序" width="450px" :mask-closable="false">
<div class="sort-wrap">
<draggable v-model="sortModal.list" item-key="id" handle=".drag-handle" animation="150">
<template #item="{ element }">
<li class="sort-item">
<span class="drag-handle">≡</span>
<span class="name">{{ element.name }}</span>
</li>
</template>
</draggable>
</div>
<template #footer>
<Button type="primary" :loading="sortModal.loading" @click="saveSort">保存排序</Button>
<Button :loading="sortModal.loading" @click="sortModal.modal = false">取消</Button>
</template>
</Modal>
<Modal v-model="uploadModelShow" :mask-closable="false" width="600" title="导入目录树">
<BschImport ref="importRef" :tempFileUrl="tempFileUrl" :uploadUrl="uploadUrl" :uploadData="uploadData"
@on-success="reloadTable" />
<template #footer>
<Button @click="uploadModelShow = false">关闭</Button>
</template>
</Modal>
</div>
</div>
</template>
<script lang="ts" setup>
import useBookInfo from "../useBookInfo";
import draggable from 'vuedraggable'
import BschImport from '@/components/BschImport.vue'
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
interface Props {
id: number;
name: string;
}
const props = withDefaults(defineProps<Props>(), {
id: 0,
name: '',
});
const { bookInfo } = useBookInfo()
const { $conf, $bus, $utils } = useCurrentInstance();
const bookId = ref<number>()
const title = computed(() => {
return props.name;
});
const refFormData = useTemplateRef('refFormData')
const refNodeNameInput = useTemplateRef('refNodeNameInput')
onBeforeMount(() => {
bookId.value = Number(props.id);
sendTable();
});
const uploadModelShow = ref(false);
const tempFileUrl = computed(() => {
let url = $conf.serviceHost + "/api/knowledge/getKnowledgeTemplate";
return url;
})
const uploadUrl = computed(() => {
return $conf.serviceHost + "/api/knowledge/importKnowledge";
})
const uploadData = computed(() => {
return { textBookId: bookId.value };
})
const editNodeModal = reactive({
id: 0,
name: '',
title: '',
type: 0,
modal: false,
loading: false,
})
const sortModal = reactive({
modal: false,
loading: false,
parentId: 0, // 当前要排序的父节点
list: [] as { id: number; name: string }[]
})
const columns = ref([
{ title: '目录树结构', key: 'name', tree: true },
{
title: '操作',
width: 300,
align: 'center',
render: (h: any, params: any) => {
const { id, name, children } = params.row;
const addChild = $utils.operatingTextHandle(h, '添加子节点', '', () => showAddNode(id));
const sortNode = $utils.operatingTextHandle(h, '子节点排序', '', () => showSortNode(params.row), !children)
const editNode = $utils.operatingTextHandle(h, '编辑', '', () => showEditNode(id, name));
const delNode = $utils.operatingTextHandle(h, '删除', 'text-error', () => showDeleteNode(id, name))
return [addChild, editNode, delNode, sortNode];
}
}
])
const tableDataComp = computed(() => {
function recursion(tree: any[], level: number): any[] {
tree.forEach(element => {
element._showChildren = true;
element.enable = element.show;
element.level = level;
if (!!element.children && element.children.length > 0)
element.children = recursion(element.children, level + 1);
else if (!element.isParent) {
delete element.children;
}
});
return tree;
}
return recursion(tableData.value, 1)
})
const { loading: tableLoading, data: tableData, send: sendTable } = useRequest(
() => Apis.Knowledge.getTreeByTextbookId({ params: { textbookId: bookId.value }, cacheFor: null }),
{
initialData: [],
immediate: false,
})
function showAddNode(pid: number) {
editNodeModal.title = '新增子节点';
editNodeModal.modal = true;
editNodeModal.id = pid;
editNodeModal.type = 1;
editNodeModal.name = '';
nextTick().then(() => {
refFormData.value?.resetFields()
refNodeNameInput.value?.focus()
})
}
function showEditNode(id: number, name: string) {
editNodeModal.title = '编辑节点';
editNodeModal.modal = true;
editNodeModal.id = id;
editNodeModal.type = 2;
nextTick().then(() => {
refFormData.value?.resetFields()
refNodeNameInput.value.focus()
editNodeModal.name = name;
})
}
function showSortNode(parent: any) {
/* 仅当存在子节点才允许排序 */
if (!parent.children || !parent.children.length) {
return Message.warning('暂无子节点,无需排序')
}
sortModal.parentId = parent.id
sortModal.list = parent.children.map((c: any) => ({ id: c.id, name: c.name }))
sortModal.modal = true
}
async function showDeleteNode(id: number, name: string) {
Modal.confirm({
title: '删除目录树节点',
content: `确定删除名为【${name}】的目录树节点记录?`,
onOk: async () => {
await Apis.Knowledge.deleteKnowledge({ params: { id } })
Message.success('删除成功!');
sendTable()
}
});
}
async function saveEditNode() {
let isAdd = editNodeModal.type == 1 ? true : false;
const validate = await refFormData.value.validate();
if (!validate) {
Message.error('请填写红色星号内容!');
return;
}
const { id, name } = editNodeModal;
editNodeModal.loading = true;
if (isAdd) {
await Apis.Knowledge.addKnowledge({ params: { name, parentId: id } })
sendTable()
}
else {
await Apis.Knowledge.updateKnowledge({ params: { name, id } })
sendTable();
}
editNodeModal.loading = false;
editNodeModal.modal = false;
}
/* 真正保存排序 */
async function saveSort() {
sortModal.loading = true
try {
/* 把排序后的 id 顺序传给后台 */
const idList = sortModal.list.map(i => i.id)
await Apis.Knowledge.updateOrderCode({ data: idList })
Message.success('排序已保存')
sortModal.modal = false
sendTable() // 刷新表格
} finally {
sortModal.loading = false
}
}
function reloadTable() {
sendTable();
}
</script>
<style lang="scss" scoped>
h5.title {
position: relative;
padding-left: 12px;
line-height: 24px;
font-size: 16px;
font-weight: 400;
&::before {
content: "";
display: block;
width: 3px;
background: #5979ea;
height: 14px;
border-radius: 4px;
position: absolute;
top: 5px;
left: 0;
}
}
.sort-wrap {
padding: 0 12px;
max-height: 420px;
overflow: auto;
}
.sort-item {
display: flex;
align-items: center;
padding: 3px 0;
border-bottom: 1px solid #f0f0f0;
.drag-handle {
font-size: 18px;
font-weight: 400;
margin-right: 8px;
color: #999;
cursor: move;
}
.name {
flex: 1;
}
}
</style>
-7
View File
@@ -1,7 +0,0 @@
import { computed } from "vue";
export default function useBookInfo() {
const bookInfo = computed(() => {
return { identity: 2, baseModId: 2000, name: "教材", path: "textbook", type: 1 };
});
return { bookInfo };
}
+3 -3
View File
@@ -291,7 +291,7 @@ function showDeleteNode() {
info: '删除后不可恢复!',
async onOk() {
try {
await Apis.SysGroup.delete({ pathParams: { id: node?.id } });
await Apis.SysGroup.sysGroupRemove({ pathParams: { id: node?.id } });
Message.success('删除成功!');
refTreePanel.value?.removeNode(node?.id);
} catch (e: any) {
@@ -313,11 +313,11 @@ async function saveEditNode() {
if (!id) {
const parentId = editNodeModal.parentId;
const data: any = { name, parentId, type: Number(editNodeModal.type) };
await Apis.SysGroup.add({ data });
await Apis.SysGroup.sysGroupAdd({ data });
Message.success('新增成功');
await refTreePanel.value?.refreshTree(parentId);
} else {
await Apis.SysGroup.edit({ pathParams: { id }, data: { name, type: Number(editNodeModal.type) } });
await Apis.SysGroup.sysGroupEdit({ pathParams: { id }, data: { name, type: Number(editNodeModal.type) } });
Message.success('编辑成功');
await refTreePanel.value?.refreshTree(id);
}