Merge branch 'master' of http://119.29.194.155:8894/zwq/zhxy-jsd
# Conflicts: # src/store/modules/user.ts
This commit is contained in:
commit
3bde948d07
@ -209,6 +209,16 @@ export const resourcesFindPageApi = async (params: any) => {
|
|||||||
return await get("/api/resources/findPage", params);
|
return await get("/api/resources/findPage", params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 教师积分查询
|
||||||
|
export const jsFindPageJfApi = async (params: any) => {
|
||||||
|
return await get("/api/js/findPageJf", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查项查询
|
||||||
|
export const inspectItemFindAllApi = async (params: any) => {
|
||||||
|
return await get("/api/inspectItem/findAlls", params);
|
||||||
|
};
|
||||||
|
|
||||||
export const resourcesSaveApi = async (params: any) => {
|
export const resourcesSaveApi = async (params: any) => {
|
||||||
return await post("/api/resources/save", params);
|
return await post("/api/resources/save", params);
|
||||||
};
|
};
|
||||||
@ -339,3 +349,13 @@ export const findAllNj = async () => {
|
|||||||
export const zwFindAllApi = async () => {
|
export const zwFindAllApi = async () => {
|
||||||
return await get("/api/zw/findAll");
|
return await get("/api/zw/findAll");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取积分详情数据
|
||||||
|
export const getByUserIdAndInspectItemIdApi = async (params: any) => {
|
||||||
|
return await get("/api/evaluation/getByUserIdAndInspectItemId", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清空用户open_id
|
||||||
|
export const clearUserOpenIdApi = async (params: { userId: string }) => {
|
||||||
|
return await post(`/api/user/clearOpenId?userId=${params.userId}`);
|
||||||
|
};
|
||||||
|
|||||||
7
src/components/BasicListLayout/index.vue
Normal file
7
src/components/BasicListLayout/index.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<ListLayout v-bind="$attrs" v-on="$listeners" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import ListLayout from './ListLayout.vue';
|
||||||
|
</script>
|
||||||
@ -389,14 +389,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/view/hr/teacherProfile/PersonalHonor",
|
"path": "pages/view/routine/JiFenPingJia/PersonalHonor",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "个人荣誉",
|
"navigationBarTitleText": "个人荣誉",
|
||||||
"enablePullDownRefresh": false
|
"enablePullDownRefresh": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/view/hr/teacherProfile/PublicClassAwards",
|
"path": "pages/view/routine/JiFenPingJia/PublicClassAwards",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "公开课获奖",
|
"navigationBarTitleText": "公开课获奖",
|
||||||
"enablePullDownRefresh": false
|
"enablePullDownRefresh": false
|
||||||
@ -555,6 +555,16 @@
|
|||||||
"navigationBarTitleText": "确认签到",
|
"navigationBarTitleText": "确认签到",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/view/routine/JiaoXueZiYuan/add-resource",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "上传资源",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationBarBackgroundColor": "#ffffff",
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"backgroundColor": "#f4f5f7"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
|
|||||||
@ -53,6 +53,7 @@
|
|||||||
class="section-block"
|
class="section-block"
|
||||||
v-for="(section, index) in sections"
|
v-for="(section, index) in sections"
|
||||||
:key="section.id"
|
:key="section.id"
|
||||||
|
v-show="hasSectionPermission(section)"
|
||||||
>
|
>
|
||||||
<view class="section-title">
|
<view class="section-title">
|
||||||
<view
|
<view
|
||||||
@ -65,7 +66,7 @@
|
|||||||
<view class="section-grid-card">
|
<view class="section-grid-card">
|
||||||
<template v-for="item in section.items" :key="item.id">
|
<template v-for="item in section.items" :key="item.id">
|
||||||
<view
|
<view
|
||||||
v-if="item.show"
|
v-if="item.show && hasPermissionDirect(item.permissionKey)"
|
||||||
class="grid-item"
|
class="grid-item"
|
||||||
@click="handleGridItemClick(item)"
|
@click="handleGridItemClick(item)"
|
||||||
>
|
>
|
||||||
@ -89,12 +90,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { jsdfindJsByPhoneApi } from "@/api/base/server";
|
import { jsdfindJsByPhoneApi, clearUserOpenIdApi } from "@/api/base/server";
|
||||||
import { useCommonStore } from "@/store/modules/common";
|
import { useCommonStore } from "@/store/modules/common";
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
import { imagUrl } from "@/utils";
|
import { imagUrl } from "@/utils";
|
||||||
import { hideLoading, showLoading } from "@/utils/uniapp";
|
import { hideLoading, showLoading } from "@/utils/uniapp";
|
||||||
import { reactive, ref } from "vue";
|
import { hasPermission } from "@/utils/permission";
|
||||||
|
import { set } from "lodash";
|
||||||
|
import { reactive, ref, computed, watch, onMounted } from "vue";
|
||||||
const { logout, getUser, getJs, setJs } = useUserStore();
|
const { logout, getUser, getJs, setJs } = useUserStore();
|
||||||
const { getZwListByLx } = useCommonStore();
|
const { getZwListByLx } = useCommonStore();
|
||||||
|
|
||||||
@ -105,10 +108,13 @@ const js = computed(() => getJs);
|
|||||||
const dzZwLabel = ref<any>("");
|
const dzZwLabel = ref<any>("");
|
||||||
const qtZwLabel = ref<any>("");
|
const qtZwLabel = ref<any>("");
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const isLoading = ref(true);
|
||||||
|
|
||||||
// 教师工作信息
|
// 教师工作信息
|
||||||
const jsWork = ref<any>({
|
const jsWork = ref<any>({
|
||||||
jf: 88,
|
jf: 88,
|
||||||
ks: 40,
|
ks: 40
|
||||||
});
|
});
|
||||||
|
|
||||||
interface GridItem {
|
interface GridItem {
|
||||||
@ -116,13 +122,14 @@ interface GridItem {
|
|||||||
icon: string; // 图标文件名 (不含扩展名)
|
icon: string; // 图标文件名 (不含扩展名)
|
||||||
text: string;
|
text: string;
|
||||||
show: boolean; // 是否显示
|
show: boolean; // 是否显示
|
||||||
// 可以添加 permissionKey 等字段
|
permissionKey?: string; // 权限键
|
||||||
path?: string; // 页面路径
|
path?: string; // 页面路径
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Section {
|
interface Section {
|
||||||
id: number | string;
|
id: number | string;
|
||||||
title: string;
|
title: string;
|
||||||
|
permissionKey?: string; // 整个区域的权限编码
|
||||||
items: GridItem[];
|
items: GridItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +138,30 @@ const handleLogout = () => {
|
|||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: "确认退出",
|
title: "确认退出",
|
||||||
content: "确定要退出登录吗?",
|
content: "确定要退出登录吗?",
|
||||||
success: (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
|
try {
|
||||||
|
// 从userdata中获取用户ID
|
||||||
|
const userDataStr = uni.getStorageSync('app-user');
|
||||||
|
let userData = null;
|
||||||
|
|
||||||
|
if (userDataStr) {
|
||||||
|
try {
|
||||||
|
userData = typeof userDataStr === 'string' ? JSON.parse(userDataStr) : userDataStr;
|
||||||
|
} catch (e) {
|
||||||
|
// 静默处理错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空用户open_id
|
||||||
|
const userId = userData?.userdata?.id || userData?.id;
|
||||||
|
if (userId) {
|
||||||
|
await clearUserOpenIdApi({ userId: userId });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 静默处理错误
|
||||||
|
}
|
||||||
|
|
||||||
// 清除用户数据
|
// 清除用户数据
|
||||||
logout();
|
logout();
|
||||||
// 跳转到登录页面
|
// 跳转到登录页面
|
||||||
@ -149,62 +178,46 @@ const sections = reactive<Section[]>([
|
|||||||
{
|
{
|
||||||
id: "routine",
|
id: "routine",
|
||||||
title: "常规",
|
title: "常规",
|
||||||
|
permissionKey: "routine", // 整个常规区域的权限编码
|
||||||
items: [
|
items: [
|
||||||
// {
|
|
||||||
// id: 10,
|
|
||||||
// text: "一师一策",
|
|
||||||
// icon: "clipboardfill",
|
|
||||||
// path: "/pages/view/routine/yishiyice/index",
|
|
||||||
// show: true,
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
id: "r2",
|
id: "r1",
|
||||||
icon: "stack-fill",
|
icon: "stack-fill",
|
||||||
text: "教学资源",
|
text: "教学资源",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-jszr", // 教学资源权限编码
|
||||||
path: "/pages/view/routine/JiaoXueZiYuan/index",
|
path: "/pages/view/routine/JiaoXueZiYuan/index",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "r5",
|
id: "r2",
|
||||||
icon: "file-mark-fill",
|
icon: "file-mark-fill",
|
||||||
text: "积分评价",
|
text: "积分评价",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-jfpj", // 积分评价权限编码
|
||||||
path: "/pages/view/routine/JiFenPingJia/JiFenPingJia",
|
path: "/pages/view/routine/JiFenPingJia/JiFenPingJia",
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// id: "r3",
|
|
||||||
// icon: "file-list-3-fil",
|
|
||||||
// text: "活动资源",
|
|
||||||
// show: true,
|
|
||||||
// path: "/pages/view/routine/HuoDongZiYuan/index",
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
id: "r3",
|
id: "r3",
|
||||||
icon: "file-list-3-fil",
|
icon: "file-list-3-fil",
|
||||||
text: "工作量",
|
text: "工作量",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-gzl", // 工作量权限编码
|
||||||
path: "/pages/view/routine/GongZuoLiang/index",
|
path: "/pages/view/routine/GongZuoLiang/index",
|
||||||
},
|
},
|
||||||
|
|
||||||
// {
|
|
||||||
// id: "r4",
|
|
||||||
// icon: "file-paper-2-fill",
|
|
||||||
// text: "公文流转",
|
|
||||||
// show: true,
|
|
||||||
// path: "/pages/view/routine/GongWenLiuZhuan/index",
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
id: "r4",
|
id: "r4",
|
||||||
icon: "file-paper-2-fill",
|
icon: "file-paper-2-fill",
|
||||||
text: "任教任职",
|
text: "任教任职",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-rzrj", // 任教任职权限编码
|
||||||
path: "/pages/view/routine/RengJiaoRengZhi/index",
|
path: "/pages/view/routine/RengJiaoRengZhi/index",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "r9",
|
id: "r5",
|
||||||
icon: "hc-fill",
|
icon: "hc-fill",
|
||||||
text: "食堂巡查",
|
text: "食堂巡查",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-stxc", // 食堂巡查权限编码
|
||||||
path: "/pages/view/routine/ShiTangXunCha/index",
|
path: "/pages/view/routine/ShiTangXunCha/index",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -212,6 +225,7 @@ const sections = reactive<Section[]>([
|
|||||||
icon: "pass-pending-fill",
|
icon: "pass-pending-fill",
|
||||||
text: "课服巡查",
|
text: "课服巡查",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-kfxc", // 课服巡查权限编码
|
||||||
path: "/pages/view/routine/kefuxuncha/xcXkList",
|
path: "/pages/view/routine/kefuxuncha/xcXkList",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -219,21 +233,23 @@ const sections = reactive<Section[]>([
|
|||||||
icon: "file-text-fill-2",
|
icon: "file-text-fill-2",
|
||||||
text: "课程介绍",
|
text: "课程介绍",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-kcjs", // 课程介绍权限编码
|
||||||
path: "/pages/base/groupTeaching/xkList",
|
path: "/pages/base/groupTeaching/xkList",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: "r8",
|
id: "r8",
|
||||||
icon: "draftfill",
|
icon: "draftfill",
|
||||||
text: "选课点名",
|
text: "选课点名",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-kcdm", // 选课点名权限编码
|
||||||
path: "/pages/base/groupTeaching/dmXkList",
|
path: "/pages/base/groupTeaching/dmXkList",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "r8",
|
id: "r9",
|
||||||
icon: "draftfill",
|
icon: "draftfill",
|
||||||
text: "发布接龙",
|
text: "发布接龙",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-bjjl", // 发布接龙权限编码
|
||||||
path: "/pages/view/notice/index",
|
path: "/pages/view/notice/index",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -241,6 +257,7 @@ const sections = reactive<Section[]>([
|
|||||||
icon: "draftfill",
|
icon: "draftfill",
|
||||||
text: "签到发布",
|
text: "签到发布",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "routine-qdfb", // 签到发布权限编码
|
||||||
path: "/pages/view/routine/qd/index",
|
path: "/pages/view/routine/qd/index",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -248,12 +265,14 @@ const sections = reactive<Section[]>([
|
|||||||
{
|
{
|
||||||
id: "home-school",
|
id: "home-school",
|
||||||
title: "家校",
|
title: "家校",
|
||||||
|
permissionKey: "home", // 整个家校区域的权限编码
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
id: "hs1",
|
id: "hs1",
|
||||||
icon: "file-text-fill",
|
icon: "file-text-fill",
|
||||||
text: "教师课表",
|
text: "教师课表",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "home-jskb", // 教师课表权限编码
|
||||||
path: "/pages/view/homeSchool/JiaoShiKeBiao",
|
path: "/pages/view/homeSchool/JiaoShiKeBiao",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -261,6 +280,7 @@ const sections = reactive<Section[]>([
|
|||||||
icon: "file-text-fill-2",
|
icon: "file-text-fill-2",
|
||||||
text: "班级课表",
|
text: "班级课表",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "home-bjkb", // 班级课表权限编码
|
||||||
path: "/pages/view/homeSchool/BanJiKeBiao",
|
path: "/pages/view/homeSchool/BanJiKeBiao",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -268,20 +288,15 @@ const sections = reactive<Section[]>([
|
|||||||
icon: "file-paper-2-fill",
|
icon: "file-paper-2-fill",
|
||||||
text: "家长通讯录",
|
text: "家长通讯录",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "home-jztxl", // 家长通讯录权限编码
|
||||||
path: "/pages/view/homeSchool/parentAddressBook/index",
|
path: "/pages/view/homeSchool/parentAddressBook/index",
|
||||||
},
|
},
|
||||||
/*{
|
|
||||||
id: "hs4",
|
|
||||||
icon: "newspaper-fill",
|
|
||||||
text: "通知列表",
|
|
||||||
show: true,
|
|
||||||
path: "/pages/view/notice/index",
|
|
||||||
},*/
|
|
||||||
{
|
{
|
||||||
id: "hs6",
|
id: "hs4",
|
||||||
icon: "filechart2fil",
|
icon: "filechart2fil",
|
||||||
text: "成绩分析",
|
text: "成绩分析",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "home-cjfx", // 成绩分析权限编码
|
||||||
path: "/pages/view/homeSchool/ChengJiFenXi",
|
path: "/pages/view/homeSchool/ChengJiFenXi",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -289,12 +304,14 @@ const sections = reactive<Section[]>([
|
|||||||
{
|
{
|
||||||
id: "hr",
|
id: "hr",
|
||||||
title: "人事",
|
title: "人事",
|
||||||
|
permissionKey: "personnel", // 整个人事区域的权限编码
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
id: "hr1",
|
id: "hr1",
|
||||||
icon: "draftfill",
|
icon: "draftfill",
|
||||||
text: "请假申请",
|
text: "请假申请",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "personnel-qjsq", // 请假申请权限编码
|
||||||
path: "/pages/view/hr/jsQj/index",
|
path: "/pages/view/hr/jsQj/index",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -302,6 +319,7 @@ const sections = reactive<Section[]>([
|
|||||||
icon: "file-user-fill",
|
icon: "file-user-fill",
|
||||||
text: "教师档案",
|
text: "教师档案",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "personnel-jsda", // 教师档案权限编码
|
||||||
path: "/pages/view/hr/teacherProfile/index",
|
path: "/pages/view/hr/teacherProfile/index",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -309,6 +327,7 @@ const sections = reactive<Section[]>([
|
|||||||
icon: "newspaper-fill",
|
icon: "newspaper-fill",
|
||||||
text: "工资条",
|
text: "工资条",
|
||||||
show: true,
|
show: true,
|
||||||
|
permissionKey: "personnel-gzt", // 工资条权限编码
|
||||||
path: "/pages/view/hr/salarySlip/index",
|
path: "/pages/view/hr/salarySlip/index",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -330,9 +349,9 @@ const getIconBgColor = (index: number) => {
|
|||||||
];
|
];
|
||||||
return colors[index % colors.length];
|
return colors[index % colors.length];
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理网格项点击事件
|
// 处理网格项点击事件
|
||||||
const handleGridItemClick = async (item: GridItem) => {
|
const handleGridItemClick = async (item: GridItem) => {
|
||||||
console.log("Clicked item:", item);
|
|
||||||
if (item.text == "教师档案") {
|
if (item.text == "教师档案") {
|
||||||
showLoading("加载中...");
|
showLoading("加载中...");
|
||||||
const res = await jsdfindJsByPhoneApi({
|
const res = await jsdfindJsByPhoneApi({
|
||||||
@ -355,6 +374,19 @@ const handleGridItemClick = async (item: GridItem) => {
|
|||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
// 初始化职务信息
|
||||||
|
await initPositionInfo();
|
||||||
|
|
||||||
|
// 完成加载
|
||||||
|
isLoading.value = false;
|
||||||
|
|
||||||
|
// 强制清除权限缓存,确保数据一致性
|
||||||
|
const { clearPermissionCachePublic } = await import('@/utils/permission');
|
||||||
|
clearPermissionCachePublic();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化职务信息
|
||||||
|
async function initPositionInfo() {
|
||||||
let dzZw: any = [];
|
let dzZw: any = [];
|
||||||
let qtZw: any = [];
|
let qtZw: any = [];
|
||||||
if (getJs.dzzw && typeof getJs.dzzw == "string") {
|
if (getJs.dzzw && typeof getJs.dzzw == "string") {
|
||||||
@ -363,25 +395,40 @@ onMounted(async () => {
|
|||||||
if (getJs.qtzw && typeof getJs.qtzw == "string") {
|
if (getJs.qtzw && typeof getJs.qtzw == "string") {
|
||||||
qtZw = getJs.qtzw.split(",");
|
qtZw = getJs.qtzw.split(",");
|
||||||
}
|
}
|
||||||
if (dzZw && dzZw.length) {
|
if (dzZw && dzZw.length){
|
||||||
const res = await getZwListByLx({ zwlx: "党政职务" });
|
const res = await getZwListByLx({ zwlx: '党政职务' });
|
||||||
dzZwLabel.value = dzZw
|
dzZwLabel.value = dzZw.map((zwId: string) => {
|
||||||
.map((zwId: string) => {
|
const zw = res.result.find((zw: any) => zwId == zw.id);
|
||||||
const zw = res.result.find((zw: any) => zwId == zw.id);
|
return zw ? zw.zwmc : '';
|
||||||
return zw ? zw.zwmc : "";
|
}).join(', ');
|
||||||
})
|
};
|
||||||
.join(", ");
|
if (qtZw && qtZw.length){
|
||||||
|
const res = await getZwListByLx({ zwlx: '其他职务' });
|
||||||
|
qtZwLabel.value = qtZw.map((zwId: string) => {
|
||||||
|
const zw = res.result.find((zw: any) => zwId == zw.id);
|
||||||
|
return zw ? zw.zwmc : '';
|
||||||
|
}).join(', ');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查区域权限
|
||||||
|
const hasSectionPermission = (section: Section) => {
|
||||||
|
if (!section.permissionKey) {
|
||||||
|
return true; // 没有权限编码的区域默认显示
|
||||||
}
|
}
|
||||||
if (qtZw && qtZw.length) {
|
return hasPermissionDirect(section.permissionKey);
|
||||||
const res = await getZwListByLx({ zwlx: "其他职务" });
|
};
|
||||||
qtZwLabel.value = qtZw
|
|
||||||
.map((zwId: string) => {
|
// 直接权限检查函数,避免缓存问题
|
||||||
const zw = res.result.find((zw: any) => zwId == zw.id);
|
const hasPermissionDirect = (permissionKey: string) => {
|
||||||
return zw ? zw.zwmc : "";
|
if (!permissionKey) return true;
|
||||||
})
|
const userStore = useUserStore();
|
||||||
.join(", ");
|
const permissions = userStore.getAuth;
|
||||||
}
|
if (!permissions || permissions.length === 0) return false;
|
||||||
});
|
|
||||||
|
const uniquePermissions = [...new Set(permissions)];
|
||||||
|
return uniquePermissions.includes(permissionKey);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -391,6 +438,47 @@ onMounted(async () => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载状态样式
|
||||||
|
.loading-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-top: 3px solid #ffffff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
// 顶部 Header
|
// 顶部 Header
|
||||||
.header-section {
|
.header-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@ -16,65 +16,104 @@ import { onLoad } from "@dcloudio/uni-app";
|
|||||||
import { useDataStore } from "@/store/modules/data";
|
import { useDataStore } from "@/store/modules/data";
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
import { checkOpenId, findJsByPhoneApi } from "@/api/system/login";
|
import { checkOpenId, findJsByPhoneApi } from "@/api/system/login";
|
||||||
|
import { PermissionCacheManager } from "@/utils/permission";
|
||||||
|
|
||||||
const { setGlobal } = useDataStore();
|
const { setGlobal } = useDataStore();
|
||||||
const { afterLoginAction } = useUserStore();
|
const { afterLoginAction } = useUserStore();
|
||||||
const { setFile, getFile } = useDataStore();
|
const { setFile, getFile } = useDataStore();
|
||||||
const isShow = ref(true);
|
const isShow = ref(true);
|
||||||
|
|
||||||
function goByJs(js: any) {
|
/**
|
||||||
console.log(js);
|
* 强制刷新权限
|
||||||
// if (js.jsType == "助教") {
|
*/
|
||||||
// uni.reLaunch({
|
async function forceRefreshPermission(changeTime?: string): Promise<void> {
|
||||||
// url: "/pages/base/groupTeaching/zhujiao",
|
try {
|
||||||
// });
|
|
||||||
// } else {
|
// 重新获取用户权限
|
||||||
if (js.confirmStatus == "A") {
|
const userStore = useUserStore();
|
||||||
uni.switchTab({
|
const currentUser = userStore.getUser;
|
||||||
url: "/pages/base/message/index",
|
|
||||||
});
|
if (currentUser && currentUser.id) {
|
||||||
} else {
|
// 重新调用权限获取接口
|
||||||
setFile({
|
const { authenticationApi } = await import('@/api/system/login');
|
||||||
...js,
|
const result = await authenticationApi({ userId: currentUser.id });
|
||||||
...getFile,
|
|
||||||
});
|
if (result && result.result) {
|
||||||
setTimeout(() => {
|
|
||||||
uni.reLaunch({
|
// 直接设置权限并刷新缓存,不调用setAuth避免重复操作
|
||||||
url: "/pages/view/hr/teacherProfile/index",
|
userStore.auth = result.result;
|
||||||
});
|
|
||||||
}, 1500);
|
// 手动刷新缓存,传递权限变更时间
|
||||||
}
|
const { refreshPermissionCache } = await import('@/utils/permission');
|
||||||
// }
|
refreshPermissionCache(result.result, changeTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('强制刷新权限失败:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goByJs(js: any) {
|
||||||
|
if (js.confirmStatus == "A") {
|
||||||
|
// 跳转到自助服务首页
|
||||||
|
uni.switchTab({
|
||||||
|
url: "/pages/base/service/index",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setFile({
|
||||||
|
...js,
|
||||||
|
...getFile,
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/view/hr/teacherProfile/index",
|
||||||
|
});
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onLoad(async (data: any) => {
|
onLoad(async (data: any) => {
|
||||||
if (data && data.openId) {
|
if (data && data.openId) {
|
||||||
setGlobal(data);
|
setGlobal(data);
|
||||||
checkOpenId({
|
|
||||||
openId: data.openId,
|
try {
|
||||||
appCode: "JS",
|
const res = await checkOpenId({
|
||||||
})
|
openId: data.openId,
|
||||||
.then(async (res: any) => {
|
appCode: "JS",
|
||||||
if (res.resultCode == 1) {
|
});
|
||||||
if (res.result) {
|
|
||||||
afterLoginAction(res.result);
|
if (res.resultCode == 1 && res.result) {
|
||||||
// 跳转页面
|
// 执行登录操作
|
||||||
goByJs(res.result.js)
|
afterLoginAction(res.result);
|
||||||
return;
|
|
||||||
|
// 如果有changeTime参数,更新权限缓存
|
||||||
|
if (data.changeTime) {
|
||||||
|
const { refreshPermissionCache } = await import('@/utils/permission');
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const currentPermissions = userStore.getAuth;
|
||||||
|
|
||||||
|
if (currentPermissions && currentPermissions.length > 0) {
|
||||||
|
refreshPermissionCache(currentPermissions, data.changeTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 跳转页面
|
||||||
|
goByJs(res.result.js);
|
||||||
|
} else {
|
||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: "/pages/system/login/login",
|
url: "/pages/system/login/login",
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
.catch((err) => {
|
} catch (err) {
|
||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: "/pages/system/login/login"
|
url: "/pages/system/login/login"
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: "/pages/system/login/login"
|
url: "/pages/system/login/login"
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -151,7 +151,7 @@ async function submit() {
|
|||||||
const params = {
|
const params = {
|
||||||
...getJs,
|
...getJs,
|
||||||
...value,
|
...value,
|
||||||
sign_file: sign_file.value,
|
signFile: sign_file.value,
|
||||||
};
|
};
|
||||||
setJs(params);
|
setJs(params);
|
||||||
const res = await jsConfirmJsDataApi(params);
|
const res = await jsConfirmJsDataApi(params);
|
||||||
|
|||||||
@ -3,12 +3,12 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<uni-card :is-shadow="false" is-full>
|
<uni-card :is-shadow="false" is-full>
|
||||||
<view class="header">
|
<view class="header">
|
||||||
<text class="score">我的得分: 84</text>
|
<text class="score">我的得分: {{ totalScore }}</text>
|
||||||
<view class="status">
|
<view class="status">
|
||||||
<text>我的状态: </text>
|
<text>我的状态: </text>
|
||||||
<view class="status-indicator"></view>
|
<view class="status-indicator"></view>
|
||||||
<view class="review-count" v-if="reviewingCount > 0">
|
<view class="review-count" v-if="reviewingCountComputed > 0">
|
||||||
{{ reviewingCount }}项在审核
|
{{ reviewingCountComputed }}项在审核
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -19,7 +19,11 @@
|
|||||||
<text class="category-header">分类</text>
|
<text class="category-header">分类</text>
|
||||||
<text class="value-header">分值</text>
|
<text class="value-header">分值</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view v-if="loading" class="loading-container">
|
||||||
|
<text class="loading-text">加载中...</text>
|
||||||
|
</view>
|
||||||
<view
|
<view
|
||||||
|
v-else
|
||||||
class="list-item"
|
class="list-item"
|
||||||
v-for="(item, index) in evaluationItems"
|
v-for="(item, index) in evaluationItems"
|
||||||
:key="index"
|
:key="index"
|
||||||
@ -42,13 +46,13 @@
|
|||||||
<view class="white-bg-color py-5">
|
<view class="white-bg-color py-5">
|
||||||
<view class="flex-row items-center pb-10 pt-5">
|
<view class="flex-row items-center pb-10 pt-5">
|
||||||
<u-button
|
<u-button
|
||||||
text="上传个人荣誉"
|
text="个人荣誉申请"
|
||||||
class="ml-15 mr-7"
|
class="ml-15 mr-7"
|
||||||
:plain="true"
|
type="primary"
|
||||||
@click="scgrry"
|
@click="scgrry"
|
||||||
/>
|
/>
|
||||||
<u-button
|
<u-button
|
||||||
text="上传公开课获奖"
|
text="公开课获奖申请"
|
||||||
class="mr-15 mr-7"
|
class="mr-15 mr-7"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="scgkkhj"
|
@click="scgkkhj"
|
||||||
@ -60,45 +64,213 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed, onMounted } from "vue";
|
||||||
|
import { jsFindPageJfApi, inspectItemFindAllApi } from "@/api/base/server";
|
||||||
|
|
||||||
const evaluationItems = ref([
|
// 响应式数据
|
||||||
{ category: "师德师风", value: 8, isUnderReview: false },
|
const evaluationItems = ref([]);
|
||||||
{ category: "考勤管理", value: 4, isUnderReview: true },
|
const totalScore = ref(0);
|
||||||
{ category: "资料上交", value: 1, isUnderReview: false },
|
const loading = ref(false);
|
||||||
{ category: "教学质量", value: 1, isUnderReview: true },
|
|
||||||
{ category: "教育科研课题", value: 8, isUnderReview: false },
|
|
||||||
{ category: "个人材料发表和获奖", value: 9, isUnderReview: true },
|
|
||||||
{ category: "展示交流和比赛", value: 4, isUnderReview: false },
|
|
||||||
{ category: "工作室活动", value: 5, isUnderReview: false },
|
|
||||||
{ category: "荣誉", value: 6, isUnderReview: true },
|
|
||||||
{ category: "辅导学生", value: 7, isUnderReview: false },
|
|
||||||
{ category: "安全管理", value: 2, isUnderReview: false },
|
|
||||||
{ category: "班级常规管理", value: 7, isUnderReview: true },
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 计算正在审核的项目数量
|
// 计算正在审核的项目数量
|
||||||
const reviewingCount = computed(() => {
|
const reviewingCountComputed = computed(() => {
|
||||||
return evaluationItems.value.filter(item => item.isUnderReview).length;
|
return evaluationItems.value.filter(item => item.isUnderReview).length;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 获取检查项数据
|
||||||
|
const loadInspectItems = async () => {
|
||||||
|
try {
|
||||||
|
const res = await inspectItemFindAllApi({ type: 2 });
|
||||||
|
if (res && res.resultCode === 1 && res.result) {
|
||||||
|
return res.result;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取检查项失败:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取教师积分数据
|
||||||
|
const loadTeacherScore = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
// 从本地缓存获取当前教师ID
|
||||||
|
const userDataStr = uni.getStorageSync('app-user');
|
||||||
|
let teacherId = '';
|
||||||
|
let userData = null;
|
||||||
|
|
||||||
|
if (userDataStr) {
|
||||||
|
try {
|
||||||
|
userData = typeof userDataStr === 'string' ? JSON.parse(userDataStr) : userDataStr;
|
||||||
|
if (userData && userData.jsData && userData.jsData.id) {
|
||||||
|
teacherId = userData.jsData.id;
|
||||||
|
console.log('当前教师ID:', teacherId);
|
||||||
|
console.log('教师信息:', userData.jsData);
|
||||||
|
} else {
|
||||||
|
console.error('未找到教师ID信息');
|
||||||
|
uni.showToast({
|
||||||
|
title: '未找到教师信息',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析用户数据失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '用户数据解析失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('未找到用户数据');
|
||||||
|
uni.showToast({
|
||||||
|
title: '未找到用户数据',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置查询参数,获取当前教师的积分数据
|
||||||
|
const params = {
|
||||||
|
startTime: new Date().getFullYear() + '-01-01', // 当年开始时间
|
||||||
|
endTime: new Date().getFullYear() + '-12-31', // 当年结束时间
|
||||||
|
pageSize: 100, // 增大页面大小,确保能获取到当前教师数据
|
||||||
|
pageNum: 1,
|
||||||
|
id: teacherId // 使用教师ID过滤
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await jsFindPageJfApi(params);
|
||||||
|
console.log('查询参数:', params);
|
||||||
|
console.log('当前教师ID:', teacherId);
|
||||||
|
console.log('API返回结果:', res);
|
||||||
|
|
||||||
|
if (res && res.rows && res.rows.length > 0) {
|
||||||
|
// 查找当前教师的数据
|
||||||
|
const teacherData = res.rows.find(row => row.id === teacherId);
|
||||||
|
|
||||||
|
if (!teacherData) {
|
||||||
|
console.warn('未找到当前教师的积分数据');
|
||||||
|
uni.showToast({
|
||||||
|
title: '未找到积分数据',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('找到的教师积分数据:', teacherData);
|
||||||
|
console.log('教师姓名:', teacherData.jsxm);
|
||||||
|
console.log('总分:', teacherData.totalScore);
|
||||||
|
console.log('积分汇总数据:', teacherData.summaries);
|
||||||
|
|
||||||
|
// 获取检查项数据
|
||||||
|
const inspectItems = await loadInspectItems();
|
||||||
|
|
||||||
|
if (inspectItems.length === 0) {
|
||||||
|
console.warn('未获取到检查项数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('检查项数据:', inspectItems);
|
||||||
|
|
||||||
|
// 构建评价项目数据,参考后端界面的getScore方法
|
||||||
|
const items = [];
|
||||||
|
let total = 0;
|
||||||
|
|
||||||
|
console.log('检查项数据:', inspectItems);
|
||||||
|
console.log('教师积分汇总:', teacherData.summaries);
|
||||||
|
|
||||||
|
inspectItems.forEach((item, index) => {
|
||||||
|
// 参考后端界面的getScore方法逻辑
|
||||||
|
let score = 0;
|
||||||
|
let num = 0;
|
||||||
|
|
||||||
|
if (teacherData.summaries && teacherData.summaries.length > 0) {
|
||||||
|
for (let i = 0; i < teacherData.summaries.length; i++) {
|
||||||
|
const summaryId = teacherData.summaries[i].inspectItemId;
|
||||||
|
const itemId = item.id;
|
||||||
|
|
||||||
|
// 使用宽松比较,并考虑大小写
|
||||||
|
if (summaryId == itemId || summaryId?.toUpperCase() == itemId?.toUpperCase()) {
|
||||||
|
score = parseFloat(teacherData.summaries[i].score) || 0;
|
||||||
|
num = parseInt(teacherData.summaries[i].num) || 0;
|
||||||
|
console.log(`✅ 匹配成功: ${item.name}, score=${score}, num=${num}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
id: item.id,
|
||||||
|
category: item.name,
|
||||||
|
value: score,
|
||||||
|
isUnderReview: num > 0, // 如果有记录数,说明在审核中
|
||||||
|
num: num
|
||||||
|
});
|
||||||
|
|
||||||
|
total += score;
|
||||||
|
});
|
||||||
|
|
||||||
|
evaluationItems.value = items;
|
||||||
|
totalScore.value = total;
|
||||||
|
|
||||||
|
console.log('处理后的积分数据:', {
|
||||||
|
items: items,
|
||||||
|
totalScore: total,
|
||||||
|
reviewingCount: reviewingCountComputed.value
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn('查询结果为空或格式不正确');
|
||||||
|
uni.showToast({
|
||||||
|
title: '未获取到积分数据',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取教师积分失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '获取积分数据失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function handleItemClick(item: any) {
|
function handleItemClick(item: any) {
|
||||||
|
// 检查该项积分是否为0
|
||||||
|
if (!item.value || item.value === 0 || item.value === '0' || item.value === 0.0 || item.value === null || item.value === undefined) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '积分为0',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `/pages/view/routine/JiFenPingJia/detail?inspectItemId=${item.id}`;
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/view/routine/JiFenPingJia/detail?id=${item.id}`,
|
url: url,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function scgrry() {
|
function scgrry() {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/view/hr/teacherProfile/PersonalHonor`,
|
url: `/pages/view/routine/JiFenPingJia/PersonalHonor`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function scgkkhj() {
|
function scgkkhj() {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/view/hr/teacherProfile/PublicClassAwards`,
|
url: `/pages/view/routine/JiFenPingJia/PublicClassAwards`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 页面加载时获取数据
|
||||||
|
onMounted(() => {
|
||||||
|
loadTeacherScore();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -147,6 +319,18 @@ function scgkkhj() {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 40rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
color: #999;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove default card padding if needed
|
// Remove default card padding if needed
|
||||||
::v-deep .uni-card .uni-card__content {
|
::v-deep .uni-card .uni-card__content {
|
||||||
padding: 10px 15px !important; // Overwrite default padding
|
padding: 10px 15px !important; // Overwrite default padding
|
||||||
|
|||||||
357
src/pages/view/routine/JiFenPingJia/PersonalHonor.vue
Normal file
357
src/pages/view/routine/JiFenPingJia/PersonalHonor.vue
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
<template>
|
||||||
|
<BasicLayout>
|
||||||
|
<view class="p-15">
|
||||||
|
<view v-if="education.xl.length > 0">
|
||||||
|
<template v-for="(item, index) in education.xl" :key="index">
|
||||||
|
<view class="po-re mb-15">
|
||||||
|
<BasicForm
|
||||||
|
v-model="item.value"
|
||||||
|
:schema="getSchemaForIndex(index)"
|
||||||
|
:index="index"
|
||||||
|
:key="`form-${index}-${forceUpdateKey}`"
|
||||||
|
:formsProps="{ labelWidth: 100 }"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
@click="deleteMemberFamily(index, item.value)"
|
||||||
|
class="delete-icon"
|
||||||
|
>
|
||||||
|
<BasicIcon type="clear" size="30" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="flex-row items-center justify-center pb-10 pt-5"
|
||||||
|
style="border: 1px solid #e8e8e8"
|
||||||
|
@click="addEducation"
|
||||||
|
>
|
||||||
|
<uni-icons type="plus" size="16" color="#447ADE"></uni-icons>
|
||||||
|
<view class="ml-5 cor-447ADE">新增</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<template #bottom>
|
||||||
|
<view class="flex-row items-center pb-10 pt-5">
|
||||||
|
<u-button
|
||||||
|
text="提交"
|
||||||
|
class="mx-15"
|
||||||
|
type="primary"
|
||||||
|
@click="submit"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</BasicLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { showToast } from "@/utils/uniapp";
|
||||||
|
import { cloneDeep, map } from "lodash";
|
||||||
|
import { fractionRuleApi } from "@/api/base/server";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
|
||||||
|
const { getJs, getUser } = useUserStore();
|
||||||
|
|
||||||
|
// 主数据
|
||||||
|
const education = reactive<any>({
|
||||||
|
xl: [{ value: {} }],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 荣誉类别数据缓存
|
||||||
|
const honorCategories = ref<any[]>([]);
|
||||||
|
|
||||||
|
// 每个表单项对应的获奖级别数据
|
||||||
|
const awardLevelsMap = reactive<Record<number, any>>({});
|
||||||
|
|
||||||
|
// 强制重新渲染的键
|
||||||
|
const forceUpdateKey = ref(0);
|
||||||
|
|
||||||
|
// 基础表单配置
|
||||||
|
const baseSchema = [
|
||||||
|
{
|
||||||
|
field: "rymc",
|
||||||
|
label: "荣誉名称",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "hilb_id",
|
||||||
|
label: "荣誉类别",
|
||||||
|
component: "BasicPicker",
|
||||||
|
componentProps: {
|
||||||
|
api: fractionRuleApi,
|
||||||
|
rangeKey: "inspectStandard",
|
||||||
|
savaKey: "id",
|
||||||
|
ok: (selectedIndex: number, form: any, list: any, attrs: any) => {
|
||||||
|
const selectedCategory = list[selectedIndex];
|
||||||
|
const formIndex = attrs.index;
|
||||||
|
|
||||||
|
// 更新当前表单项的获奖级别选项
|
||||||
|
updateAwardLevels(formIndex, selectedCategory);
|
||||||
|
|
||||||
|
// 清空已选择的获奖级别(如果之前有选择的话)
|
||||||
|
if (education.xl[formIndex].value.hjjbId) {
|
||||||
|
education.xl[formIndex].value.hjjbId = "";
|
||||||
|
}
|
||||||
|
// 强制重新渲染
|
||||||
|
forceUpdateKey.value++;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "hjjbId",
|
||||||
|
label: "获奖级别",
|
||||||
|
component: "BasicPicker",
|
||||||
|
componentProps: {
|
||||||
|
range: [],
|
||||||
|
rangeKey: "name",
|
||||||
|
savaKey: "id",
|
||||||
|
open: (value: any, attrs: any, model: any) => {
|
||||||
|
const formIndex = attrs.index;
|
||||||
|
// 检查是否已选择荣誉类别
|
||||||
|
if (!model?.hilb_id) {
|
||||||
|
showToast({
|
||||||
|
title: "请先选择荣誉类别",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有对应的获奖级别数据
|
||||||
|
const awardLevels = awardLevelsMap[formIndex] || [];
|
||||||
|
|
||||||
|
if (awardLevels.length === 0) {
|
||||||
|
showToast({
|
||||||
|
title: "该荣誉类别暂无获奖级别数据",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "bjdw",
|
||||||
|
label: "颁奖单位",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "hjtime",
|
||||||
|
label: "获奖时间",
|
||||||
|
component: "BasicDateTimes",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "jf",
|
||||||
|
label: "积分",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "hjfjId",
|
||||||
|
label: "上传证书",
|
||||||
|
component: "BasicUpload",
|
||||||
|
itemProps: {
|
||||||
|
labelPosition: "top",
|
||||||
|
},
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 为每个表单项生成动态的schema
|
||||||
|
const getSchemaForIndex = (index: number) => {
|
||||||
|
const schema = cloneDeep(baseSchema);
|
||||||
|
|
||||||
|
// 更新获奖级别的选项数据
|
||||||
|
const hjjbField = schema.find((item) => item.field === "hjjbId");
|
||||||
|
if (hjjbField) {
|
||||||
|
hjjbField.componentProps.range = awardLevelsMap[index] || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return schema;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新指定表单项的获奖级别选项
|
||||||
|
const updateAwardLevels = (formIndex: number, category: any) => {
|
||||||
|
if (category?.ruleItemList && category.ruleItemList.length > 0) {
|
||||||
|
awardLevelsMap[formIndex] = category.ruleItemList;
|
||||||
|
} else {
|
||||||
|
awardLevelsMap[formIndex] = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化荣誉类别数据
|
||||||
|
const initHonorCategories = async () => {
|
||||||
|
try {
|
||||||
|
const result = await fractionRuleApi();
|
||||||
|
honorCategories.value = result.result || result || [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取荣誉类别数据失败:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化回显数据
|
||||||
|
const initEchoData = async () => {
|
||||||
|
await initHonorCategories();
|
||||||
|
|
||||||
|
// 为每个已有数据的表单项初始化获奖级别选项
|
||||||
|
education.xl.forEach((formItem: any, index: number) => {
|
||||||
|
if (formItem.value?.hilb_id) {
|
||||||
|
const category = honorCategories.value.find(
|
||||||
|
(cat: any) => cat.id === formItem.value.hilb_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
// 更新获奖级别选项
|
||||||
|
updateAwardLevels(index, category);
|
||||||
|
} else {
|
||||||
|
console.log(`未找到荣誉类别 ID: ${formItem.value.hilb_id}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(`表单项 ${index} 没有荣誉类别 ID`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 强制重新渲染以确保获奖级别能正确显示
|
||||||
|
forceUpdateKey.value++;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加新的教育项
|
||||||
|
function addEducation() {
|
||||||
|
const newIndex = education.xl.length;
|
||||||
|
education.xl.push({ value: {} });
|
||||||
|
|
||||||
|
// 为新项初始化空的获奖级别选项
|
||||||
|
awardLevelsMap[newIndex] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除教育项
|
||||||
|
function deleteMemberFamily(index: number, item: any) {
|
||||||
|
// 删除对应的获奖级别数据
|
||||||
|
delete awardLevelsMap[index];
|
||||||
|
|
||||||
|
// 重新整理awardLevelsMap的键值
|
||||||
|
const newAwardLevelsMap: Record<number, any[]> = {};
|
||||||
|
education.xl.forEach((_: any, i: number) => {
|
||||||
|
if (i < index) {
|
||||||
|
newAwardLevelsMap[i] = awardLevelsMap[i] || [];
|
||||||
|
} else if (i > index) {
|
||||||
|
newAwardLevelsMap[i - 1] = awardLevelsMap[i] || [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除表单项
|
||||||
|
education.xl.splice(index, 1);
|
||||||
|
|
||||||
|
// 更新awardLevelsMap
|
||||||
|
Object.keys(awardLevelsMap).forEach(
|
||||||
|
(key: string) => delete awardLevelsMap[Number(key)]
|
||||||
|
);
|
||||||
|
Object.assign(awardLevelsMap, newAwardLevelsMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交数据
|
||||||
|
async function submit() {
|
||||||
|
try {
|
||||||
|
// 验证表单数据
|
||||||
|
const grRyList = map(education.xl, (item) => {
|
||||||
|
return { ...item.value, hjlxId: "GRRY" };
|
||||||
|
});
|
||||||
|
|
||||||
|
if (grRyList.length === 0) {
|
||||||
|
showToast({
|
||||||
|
title: "请至少添加一条荣誉记录",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证必填字段
|
||||||
|
for (let i = 0; i < grRyList.length; i++) {
|
||||||
|
const item = grRyList[i];
|
||||||
|
if (!item.rymc) {
|
||||||
|
showToast({
|
||||||
|
title: `第${i + 1}条记录:请填写荣誉名称`,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!item.hilb_id) {
|
||||||
|
showToast({
|
||||||
|
title: `第${i + 1}条记录:请选择荣誉类别`,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!item.hjjbId) {
|
||||||
|
showToast({
|
||||||
|
title: `第${i + 1}条记录:请选择获奖级别`,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!item.bjdw) {
|
||||||
|
showToast({
|
||||||
|
title: `第${i + 1}条记录:请填写颁奖单位`,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!item.hjtime) {
|
||||||
|
showToast({
|
||||||
|
title: `第${i + 1}条记录:请选择获奖时间`,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!item.jf) {
|
||||||
|
showToast({
|
||||||
|
title: `第${i + 1}条记录:请填写积分`,
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建提交参数
|
||||||
|
const params = {
|
||||||
|
id: null, // 新增申请
|
||||||
|
jsId: getJs.id,
|
||||||
|
jsName: getJs.jsxm,
|
||||||
|
grRyList: grRyList,
|
||||||
|
// 积分申请相关字段
|
||||||
|
inspectStandard: "个人荣誉申请",
|
||||||
|
scoreType: "1", // 加分
|
||||||
|
examineTime: new Date(),
|
||||||
|
remark: "个人荣誉积分申请",
|
||||||
|
};
|
||||||
|
|
||||||
|
uni.showLoading({ title: "提交中..." });
|
||||||
|
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("提交积分申请失败:", error);
|
||||||
|
showToast({
|
||||||
|
title: "提交失败,请稍后重试",
|
||||||
|
icon: "none"
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面加载时初始化
|
||||||
|
onMounted(() => {
|
||||||
|
initHonorCategories();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.delete-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: -13px;
|
||||||
|
top: -14px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
284
src/pages/view/routine/JiFenPingJia/PublicClassAwards.vue
Normal file
284
src/pages/view/routine/JiFenPingJia/PublicClassAwards.vue
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
<template>
|
||||||
|
<BasicLayout>
|
||||||
|
<view class="p-15">
|
||||||
|
<view v-if="education.xl.length > 0">
|
||||||
|
<template v-for="(item, index) in education.xl" :key="index">
|
||||||
|
<view class="po-re mb-15">
|
||||||
|
<BasicForm
|
||||||
|
v-model="item.value"
|
||||||
|
:schema="getSchemaForIndex(index)"
|
||||||
|
:index="index"
|
||||||
|
:key="`form-${index}-${forceUpdateKey}`"
|
||||||
|
:formsProps="{ labelWidth: 100 }"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
@click="deleteMemberFamily(index, item.value)"
|
||||||
|
class="delete-icon"
|
||||||
|
>
|
||||||
|
<BasicIcon type="clear" size="30" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="flex-row items-center justify-center pb-10 pt-5"
|
||||||
|
style="border: 1px solid #e8e8e8"
|
||||||
|
@click="addEducation"
|
||||||
|
>
|
||||||
|
<uni-icons type="plus" size="16" color="#447ADE"></uni-icons>
|
||||||
|
<view class="ml-5 cor-447ADE">新增</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<template #bottom>
|
||||||
|
<view class="flex-row items-center pb-10 pt-5">
|
||||||
|
<u-button text="提交" class="mx-15" type="primary" @click="submit" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</BasicLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { fractionRuleApi1 } from "@/api/base/server";
|
||||||
|
import { showToast } from "@/utils/uniapp";
|
||||||
|
import { cloneDeep, map } from "lodash";
|
||||||
|
|
||||||
|
// 主数据
|
||||||
|
const education = reactive<any>({
|
||||||
|
xl: [{ value: {} }],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 荣誉类别数据缓存
|
||||||
|
const honorCategories = ref<any[]>([]);
|
||||||
|
|
||||||
|
// 每个表单项对应的获奖级别数据
|
||||||
|
const awardLevelsMap = reactive<Record<number, any>>({});
|
||||||
|
|
||||||
|
// 强制重新渲染的键
|
||||||
|
const forceUpdateKey = ref(0);
|
||||||
|
|
||||||
|
// 基础表单配置
|
||||||
|
const baseSchema = [
|
||||||
|
{
|
||||||
|
field: "rymc",
|
||||||
|
label: "荣誉名称",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "hilb_id",
|
||||||
|
label: "荣誉类别",
|
||||||
|
component: "BasicPicker",
|
||||||
|
componentProps: {
|
||||||
|
api: fractionRuleApi1,
|
||||||
|
rangeKey: "inspectStandard",
|
||||||
|
savaKey: "id",
|
||||||
|
ok: (selectedIndex: number, form: any, list: any, attrs: any) => {
|
||||||
|
const selectedCategory = list[selectedIndex];
|
||||||
|
const formIndex = attrs.index;
|
||||||
|
|
||||||
|
// 更新当前表单项的获奖级别选项
|
||||||
|
updateAwardLevels(formIndex, selectedCategory);
|
||||||
|
|
||||||
|
// 清空已选择的获奖级别(如果之前有选择的话)
|
||||||
|
if (education.xl[formIndex].value.xm) {
|
||||||
|
education.xl[formIndex].value.xm = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强制重新渲染
|
||||||
|
forceUpdateKey.value++;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "xm",
|
||||||
|
label: "获奖级别",
|
||||||
|
component: "BasicPicker",
|
||||||
|
componentProps: {
|
||||||
|
range: [],
|
||||||
|
rangeKey: "name",
|
||||||
|
savaKey: "id",
|
||||||
|
open: (value: any, attrs: any, model: any) => {
|
||||||
|
const formIndex = attrs.index;
|
||||||
|
|
||||||
|
// 检查是否已选择荣誉类别
|
||||||
|
if (!model?.hilb_id) {
|
||||||
|
showToast({
|
||||||
|
title: "请先选择荣誉类别",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有对应的获奖级别数据
|
||||||
|
const awardLevels = awardLevelsMap[formIndex] || [];
|
||||||
|
|
||||||
|
if (awardLevels.length === 0) {
|
||||||
|
showToast({
|
||||||
|
title: "该荣誉类别暂无获奖级别数据",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "bjdw",
|
||||||
|
label: "颁奖单位",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "hjtime",
|
||||||
|
label: "获奖时间",
|
||||||
|
component: "BasicDateTimes",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "jf",
|
||||||
|
label: "积分",
|
||||||
|
component: "BasicInput",
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "hjfjId",
|
||||||
|
label: "上传证书",
|
||||||
|
component: "BasicUpload",
|
||||||
|
required: true,
|
||||||
|
itemProps: {
|
||||||
|
labelPosition: "top",
|
||||||
|
},
|
||||||
|
componentProps: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 为每个表单项生成动态的schema
|
||||||
|
const getSchemaForIndex = (index: number) => {
|
||||||
|
const schema = cloneDeep(baseSchema);
|
||||||
|
|
||||||
|
// 更新获奖级别的选项数据
|
||||||
|
const hjjbField = schema.find((item) => item.field === "xm");
|
||||||
|
if (hjjbField) {
|
||||||
|
hjjbField.componentProps.range = awardLevelsMap[index] || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return schema;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新指定表单项的获奖级别选项
|
||||||
|
const updateAwardLevels = (formIndex: number, category: any) => {
|
||||||
|
if (category?.ruleItemList && category.ruleItemList.length > 0) {
|
||||||
|
awardLevelsMap[formIndex] = category.ruleItemList;
|
||||||
|
} else {
|
||||||
|
awardLevelsMap[formIndex] = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化荣誉类别数据
|
||||||
|
const initHonorCategories = async () => {
|
||||||
|
try {
|
||||||
|
const result = await fractionRuleApi1();
|
||||||
|
honorCategories.value = result.result || result || [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取荣誉类别数据失败:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化回显数据
|
||||||
|
const initEchoData = async () => {
|
||||||
|
await initHonorCategories();
|
||||||
|
|
||||||
|
// 为每个已有数据的表单项初始化获奖级别选项
|
||||||
|
education.xl.forEach((formItem: any, index: number) => {
|
||||||
|
if (formItem.value?.hilb_id) {
|
||||||
|
const category = honorCategories.value.find(
|
||||||
|
(cat: any) => cat.id === formItem.value.hilb_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
// 更新获奖级别选项
|
||||||
|
updateAwardLevels(index, category);
|
||||||
|
} else {
|
||||||
|
console.log(`未找到荣誉类别 ID: ${formItem.value.hilb_id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 强制重新渲染以确保获奖级别能正确显示
|
||||||
|
forceUpdateKey.value++;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加新的教育项
|
||||||
|
function addEducation() {
|
||||||
|
const newIndex = education.xl.length;
|
||||||
|
education.xl.push({ value: {} });
|
||||||
|
|
||||||
|
// 为新项初始化空的获奖级别选项
|
||||||
|
awardLevelsMap[newIndex] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除教育项
|
||||||
|
function deleteMemberFamily(index: number, item: any) {
|
||||||
|
// 删除对应的获奖级别数据
|
||||||
|
delete awardLevelsMap[index];
|
||||||
|
|
||||||
|
// 重新整理awardLevelsMap的键值
|
||||||
|
const newAwardLevelsMap: Record<number, any[]> = {};
|
||||||
|
education.xl.forEach((_: any, i: number) => {
|
||||||
|
if (i < index) {
|
||||||
|
newAwardLevelsMap[i] = awardLevelsMap[i] || [];
|
||||||
|
} else if (i > index) {
|
||||||
|
newAwardLevelsMap[i - 1] = awardLevelsMap[i] || [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除表单项
|
||||||
|
education.xl.splice(index, 1);
|
||||||
|
|
||||||
|
// 更新awardLevelsMap
|
||||||
|
Object.keys(awardLevelsMap).forEach(
|
||||||
|
(key: string) => delete awardLevelsMap[Number(key)]
|
||||||
|
);
|
||||||
|
Object.assign(awardLevelsMap, newAwardLevelsMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交数据
|
||||||
|
function submit() {
|
||||||
|
const gkkRyList = map(education.xl, (item) => {
|
||||||
|
return { ...item.value, hjlxId: "GKKHJQK" };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 初始化数据
|
||||||
|
// const { getFile, setFile } = useDataStore();
|
||||||
|
|
||||||
|
// // 处理回显数据
|
||||||
|
// if (getFile.gkkRyList && getFile.gkkRyList.length > 0) {
|
||||||
|
// education.xl = map(getFile.gkkRyList, (item) => {
|
||||||
|
// return { value: item };
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 页面加载时初始化
|
||||||
|
onMounted(() => {
|
||||||
|
// if (getFile.gkkRyList && getFile.gkkRyList.length > 0) {
|
||||||
|
// // 有回显数据时,延迟初始化确保数据正确加载
|
||||||
|
// nextTick(() => {
|
||||||
|
// initEchoData();
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// // 无回显数据时,只需要初始化荣誉类别
|
||||||
|
// initHonorCategories();
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.delete-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: -13px;
|
||||||
|
top: -14px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -46,14 +46,14 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 证明材料 -->
|
<!-- 证明材料 -->
|
||||||
<view class="detail-item file-section" v-if="detailData.files.length > 0">
|
<view class="detail-item file-section" v-if="detailData.files && detailData.files.length > 0">
|
||||||
<text class="detail-label">证明材料</text>
|
<text class="detail-label">证明材料</text>
|
||||||
<view class="file-list">
|
<view class="file-list">
|
||||||
<view
|
<view
|
||||||
class="file-item"
|
class="file-item"
|
||||||
v-for="(file, index) in detailData.files"
|
v-for="(file, index) in detailData.files"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="previewFile(file)"
|
@click="handlePreviewFile(file)"
|
||||||
>
|
>
|
||||||
<uni-icons type="paperplane" size="16" color="#409eff" />
|
<uni-icons type="paperplane" size="16" color="#409eff" />
|
||||||
<text class="file-name">{{ file.name }}</text>
|
<text class="file-name">{{ file.name }}</text>
|
||||||
@ -61,7 +61,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 转手机端按钮 -->
|
<!-- 返回按钮 -->
|
||||||
<view class="bottom-actions">
|
<view class="bottom-actions">
|
||||||
<button class="mobile-btn" @click="goBack">返回</button>
|
<button class="mobile-btn" @click="goBack">返回</button>
|
||||||
</view>
|
</view>
|
||||||
@ -71,6 +71,18 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
|
import { onLoad } from "@dcloudio/uni-app";
|
||||||
|
import { imagUrl } from "@/utils";
|
||||||
|
import { getByUserIdAndInspectItemIdApi } from "@/api/base/server";
|
||||||
|
import {
|
||||||
|
isVideo,
|
||||||
|
isImage,
|
||||||
|
canPreview,
|
||||||
|
previewFile,
|
||||||
|
previewVideo,
|
||||||
|
previewImage,
|
||||||
|
downloadFile
|
||||||
|
} from "@/utils/filePreview";
|
||||||
|
|
||||||
interface DetailData {
|
interface DetailData {
|
||||||
evaluationType: string;
|
evaluationType: string;
|
||||||
@ -79,77 +91,208 @@ interface DetailData {
|
|||||||
department: string;
|
department: string;
|
||||||
evaluationDate: string;
|
evaluationDate: string;
|
||||||
score: number | string;
|
score: number | string;
|
||||||
files: Array<{ name: string; url: string }>;
|
files: Array<{ name: string; url: string; resSuf?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 详情数据
|
// 详情数据
|
||||||
const detailData = ref<DetailData>({
|
const detailData = ref<DetailData>({
|
||||||
evaluationType: "考核评价",
|
evaluationType: "",
|
||||||
scoreType: "加分",
|
scoreType: "",
|
||||||
scoreValue: 1,
|
scoreValue: 0,
|
||||||
department: "教科处",
|
department: "",
|
||||||
evaluationDate: "2025-06-08",
|
evaluationDate: "",
|
||||||
score: 90,
|
score: 0,
|
||||||
files: [
|
files: [],
|
||||||
{ name: "教学成果证明.pdf", url: "/files/certificate.pdf" },
|
|
||||||
{ name: "获奖证书.jpg", url: "/files/award.jpg" },
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 页面参数
|
||||||
|
const pageParams = ref({
|
||||||
|
inspectItemId: '',
|
||||||
|
userId: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取详情数据
|
||||||
|
const loadDetailData = async () => {
|
||||||
|
try {
|
||||||
|
const { inspectItemId, userId } = pageParams.value;
|
||||||
|
|
||||||
|
console.log('页面参数:', pageParams.value);
|
||||||
|
|
||||||
|
if (!inspectItemId || !userId) {
|
||||||
|
console.error('缺少必要参数');
|
||||||
|
uni.showToast({
|
||||||
|
title: '参数错误',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用API获取详情数据
|
||||||
|
const res = await getByUserIdAndInspectItemIdApi({
|
||||||
|
userId: userId,
|
||||||
|
inspectItemId: inspectItemId
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('API返回数据:', res);
|
||||||
|
|
||||||
|
if (res && res.resultCode === 1 && res.result) {
|
||||||
|
const data = res.result;
|
||||||
|
|
||||||
|
// 处理返回的数据结构
|
||||||
|
detailData.value = {
|
||||||
|
evaluationType: data.evaluations?.[0]?.itemName || "考核评价",
|
||||||
|
scoreType: data.evaluations?.[0]?.scoreType === "1" ? "加分" : "扣分",
|
||||||
|
scoreValue: data.evaluations?.[0]?.score || 0,
|
||||||
|
department: data.evaluations?.[0]?.departmentName || "教科处",
|
||||||
|
evaluationDate: data.evaluations?.[0]?.examineTime || "",
|
||||||
|
score: data.score || 0,
|
||||||
|
files: data.evaluations?.[0]?.pic ? [
|
||||||
|
{
|
||||||
|
name: "证明材料",
|
||||||
|
url: data.evaluations[0].pic,
|
||||||
|
resSuf: data.evaluations[0].pic.split(".").pop()?.toLowerCase() || ""
|
||||||
|
}
|
||||||
|
] : []
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('处理后的详情数据:', detailData.value);
|
||||||
|
} else {
|
||||||
|
console.warn('API返回数据为空或格式不正确');
|
||||||
|
uni.showToast({
|
||||||
|
title: '未获取到详情数据',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取详情数据失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '获取数据失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 返回上一页
|
// 返回上一页
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 预览文件
|
// 文件预览处理(参考教学资源的预览方式)
|
||||||
const previewFile = (file: { name: string; url: string }) => {
|
const handlePreviewFile = (file: { name: string; url: string; resSuf?: string }) => {
|
||||||
// 根据文件类型进行预览
|
const fileUrl = imagUrl(file.url);
|
||||||
const ext = file.name.split(".").pop()?.toLowerCase();
|
const fileName = file.name;
|
||||||
|
const fileExt = file.resSuf || file.name.split(".").pop()?.toLowerCase() || "";
|
||||||
|
|
||||||
if (["jpg", "jpeg", "png", "gif"].includes(ext || "")) {
|
console.log('预览文件:', {
|
||||||
|
name: fileName,
|
||||||
|
url: fileUrl,
|
||||||
|
ext: fileExt
|
||||||
|
});
|
||||||
|
|
||||||
|
// 根据文件类型进行预览
|
||||||
|
if (isVideo(fileExt)) {
|
||||||
|
// 视频预览
|
||||||
|
previewVideo(fileUrl, fileName)
|
||||||
|
.then(() => {
|
||||||
|
console.log('视频预览成功');
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('视频预览失败:', error);
|
||||||
|
// 预览失败时尝试下载
|
||||||
|
handleDownloadFile(file);
|
||||||
|
});
|
||||||
|
} else if (isImage(fileExt)) {
|
||||||
// 图片预览
|
// 图片预览
|
||||||
uni.previewImage({
|
previewImage(fileUrl)
|
||||||
urls: [file.url],
|
.then(() => {
|
||||||
current: file.url,
|
console.log('图片预览成功');
|
||||||
});
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('图片预览失败:', error);
|
||||||
|
handleDownloadFile(file);
|
||||||
|
});
|
||||||
|
} else if (canPreview(fileExt)) {
|
||||||
|
// 可预览文件
|
||||||
|
previewFile(fileUrl, fileName, fileExt)
|
||||||
|
.then(() => {
|
||||||
|
console.log('文件预览成功');
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('文件预览失败:', error);
|
||||||
|
handleDownloadFile(file);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// 其他文件类型提示下载
|
// 不可预览文件,直接下载
|
||||||
uni.showModal({
|
handleDownloadFile(file);
|
||||||
title: "提示",
|
|
||||||
content: `是否下载文件: ${file.name}?`,
|
|
||||||
success: (res) => {
|
|
||||||
if (res.confirm) {
|
|
||||||
// TODO: 实现文件下载逻辑
|
|
||||||
uni.showToast({
|
|
||||||
title: "开始下载",
|
|
||||||
icon: "success",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 转手机端
|
// 文件下载处理
|
||||||
const transferToMobile = () => {
|
const handleDownloadFile = (file: { name: string; url: string }) => {
|
||||||
|
const fileUrl = imagUrl(file.url);
|
||||||
|
const fileName = file.name;
|
||||||
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: "提示",
|
title: "提示",
|
||||||
content: "确定要转到手机端处理吗?",
|
content: `是否下载文件: ${fileName}?`,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
// TODO: 实现转手机端逻辑
|
downloadFile(fileUrl, fileName)
|
||||||
uni.showToast({
|
.then(() => {
|
||||||
title: "已转至手机端",
|
uni.showToast({
|
||||||
icon: "success",
|
title: "下载成功",
|
||||||
});
|
icon: "success",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('下载失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: "下载失败",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 页面加载时可以获取详情数据
|
// onLoad会自动执行,不需要在这里调用
|
||||||
console.log("页面加载完成");
|
});
|
||||||
|
|
||||||
|
// 调用onLoad生命周期
|
||||||
|
onLoad((options) => {
|
||||||
|
console.log('onLoad被调用,参数:', options);
|
||||||
|
|
||||||
|
// 从URL获取inspectItemId
|
||||||
|
const inspectItemId = options.inspectItemId || '';
|
||||||
|
|
||||||
|
// 从缓存获取教师ID
|
||||||
|
let userId = '';
|
||||||
|
const userDataStr = uni.getStorageSync('app-user');
|
||||||
|
if (userDataStr) {
|
||||||
|
try {
|
||||||
|
const userData = typeof userDataStr === 'string' ? JSON.parse(userDataStr) : userDataStr;
|
||||||
|
if (userData && userData.jsData && userData.jsData.id) {
|
||||||
|
userId = userData.jsData.id;
|
||||||
|
console.log('从缓存获取到教师ID:', userId);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析用户数据失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置页面参数
|
||||||
|
pageParams.value = {
|
||||||
|
inspectItemId: inspectItemId,
|
||||||
|
userId: userId
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('最终页面参数:', pageParams.value);
|
||||||
|
|
||||||
|
// 加载详情数据
|
||||||
|
loadDetailData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -225,11 +368,17 @@ onMounted(() => {
|
|||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
margin-bottom: 10rpx;
|
margin-bottom: 10rpx;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #e6f7ff;
|
background-color: #e6f7ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
background-color: #d4f1ff;
|
||||||
|
}
|
||||||
|
|
||||||
uni-icons {
|
uni-icons {
|
||||||
margin-right: 10rpx;
|
margin-right: 10rpx;
|
||||||
}
|
}
|
||||||
@ -259,7 +408,7 @@ onMounted(() => {
|
|||||||
.mobile-btn {
|
.mobile-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 88rpx;
|
height: 88rpx;
|
||||||
background-color: #ff4757;
|
background-color: #409eff;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -270,7 +419,7 @@ onMounted(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
background-color: #ff3742;
|
background-color: #337ecc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
700
src/pages/view/routine/JiaoXueZiYuan/add-resource.vue
Normal file
700
src/pages/view/routine/JiaoXueZiYuan/add-resource.vue
Normal file
@ -0,0 +1,700 @@
|
|||||||
|
<template>
|
||||||
|
<view class="add-resource-page">
|
||||||
|
<!-- 页面头部 -->
|
||||||
|
<view class="page-header">
|
||||||
|
<view class="header-left" @click="goBack">
|
||||||
|
<uni-icons type="left" size="20" color="#333"></uni-icons>
|
||||||
|
<text class="back-text">返回</text>
|
||||||
|
</view>
|
||||||
|
<view class="header-title">上传资源</view>
|
||||||
|
<view class="header-right"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 表单内容 -->
|
||||||
|
<scroll-view scroll-y class="form-scroll-view">
|
||||||
|
<view class="form-container">
|
||||||
|
<!-- 资源目录 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">资源目录 <text class="required">*</text></text>
|
||||||
|
<picker
|
||||||
|
mode="selector"
|
||||||
|
:range="treeData"
|
||||||
|
range-key="title"
|
||||||
|
@change="handleResourceTypeChange"
|
||||||
|
>
|
||||||
|
<view class="picker-row">
|
||||||
|
<text :class="{ placeholder: !formData.resourType }">
|
||||||
|
{{ getResourceTypeText() || '请选择资源目录' }}
|
||||||
|
</text>
|
||||||
|
<uni-icons type="right" size="16" color="#999"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 课题名称 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">课题名称 <text class="required">*</text></text>
|
||||||
|
<uni-easyinput
|
||||||
|
v-model="formData.resourName"
|
||||||
|
placeholder="请输入课题名称"
|
||||||
|
:inputBorder="false"
|
||||||
|
class="content-input"
|
||||||
|
></uni-easyinput>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 课时 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">课时 <text class="required">*</text></text>
|
||||||
|
<uni-easyinput
|
||||||
|
v-model="formData.hour"
|
||||||
|
placeholder="请输入课时"
|
||||||
|
type="number"
|
||||||
|
:inputBorder="false"
|
||||||
|
class="content-input"
|
||||||
|
></uni-easyinput>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 资源类别 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">资源类别 <text class="required">*</text></text>
|
||||||
|
<picker
|
||||||
|
mode="selector"
|
||||||
|
:range="categoryOptions"
|
||||||
|
range-key="label"
|
||||||
|
@change="handleCategoryChange"
|
||||||
|
>
|
||||||
|
<view class="picker-row">
|
||||||
|
<text :class="{ placeholder: !formData.category }">
|
||||||
|
{{ getCategoryText() || '请选择资源类别' }}
|
||||||
|
</text>
|
||||||
|
<uni-icons type="right" size="16" color="#999"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 资源描述 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">资源描述</text>
|
||||||
|
<uni-easyinput
|
||||||
|
type="textarea"
|
||||||
|
autoHeight
|
||||||
|
v-model="formData.content"
|
||||||
|
placeholder="请输入资源描述"
|
||||||
|
:inputBorder="false"
|
||||||
|
class="content-input"
|
||||||
|
></uni-easyinput>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 上传资源 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">上传资源 <text class="required">*</text></text>
|
||||||
|
<view class="attachment-list">
|
||||||
|
<view
|
||||||
|
v-for="(att, index) in formData.attachments"
|
||||||
|
:key="index"
|
||||||
|
class="attachment-item"
|
||||||
|
>
|
||||||
|
<uni-icons
|
||||||
|
:type="getAttachmentIcon(att.type)"
|
||||||
|
size="20"
|
||||||
|
color="#666"
|
||||||
|
class="attachment-icon"
|
||||||
|
></uni-icons>
|
||||||
|
<text class="attachment-name" @click="previewAttachment(att)">{{
|
||||||
|
att.name
|
||||||
|
}}</text>
|
||||||
|
<uni-icons
|
||||||
|
type="closeempty"
|
||||||
|
size="18"
|
||||||
|
color="#999"
|
||||||
|
class="remove-icon"
|
||||||
|
@click="removeAttachment(index)"
|
||||||
|
></uni-icons>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="add-attachment-placeholder" @click="addAttachment">
|
||||||
|
<view class="add-icon"
|
||||||
|
><uni-icons type="plusempty" size="20" color="#ccc"></uni-icons
|
||||||
|
></view>
|
||||||
|
<text class="placeholder-text">添加图文/视频/文件</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 底部提交按钮 -->
|
||||||
|
<view class="bottom-actions">
|
||||||
|
<button class="action-btn cancel-btn" @click="goBack">
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<button class="action-btn confirm-btn" @click="handleSubmitForm" :disabled="isSubmitting">
|
||||||
|
{{ isSubmitting ? '提交中...' : '提交' }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { resourcesSaveApi } from "@/api/base/server";
|
||||||
|
import { typesFindTreeApi } from "@/api/base/server";
|
||||||
|
import { attachmentUpload } from "@/api/system/upload";
|
||||||
|
import { imagUrl } from "@/utils";
|
||||||
|
import { useDicStore } from "@/store/modules/dic";
|
||||||
|
|
||||||
|
const { findByPid } = useDicStore();
|
||||||
|
|
||||||
|
interface Attachment {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
url: string;
|
||||||
|
size?: number;
|
||||||
|
path?: string;
|
||||||
|
id?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const formData = reactive({
|
||||||
|
resourName: '',
|
||||||
|
resourType: '',
|
||||||
|
category: '',
|
||||||
|
content: '',
|
||||||
|
fileId: '',
|
||||||
|
filePath: '',
|
||||||
|
resSuf: '',
|
||||||
|
hour: '',
|
||||||
|
id: '',
|
||||||
|
fileName: '',
|
||||||
|
attachments: [] as Attachment[] // 新增附件列表
|
||||||
|
});
|
||||||
|
|
||||||
|
// 树形数据
|
||||||
|
const treeData = ref([]);
|
||||||
|
|
||||||
|
// 提交状态
|
||||||
|
const isSubmitting = ref(false);
|
||||||
|
|
||||||
|
// 资源类别选项 - 从字典表获取
|
||||||
|
const categoryOptions = ref([]);
|
||||||
|
|
||||||
|
// 加载资源类别数据
|
||||||
|
const loadCategoryOptions = async () => {
|
||||||
|
try {
|
||||||
|
const result = await findByPid({ pid: 1391443399 });
|
||||||
|
if (result && Array.isArray(result)) {
|
||||||
|
categoryOptions.value = result.map(item => ({
|
||||||
|
value: item.dictionaryCode,
|
||||||
|
label: item.dictionaryValue
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载资源类别失败:', error);
|
||||||
|
// 如果加载失败,使用默认选项
|
||||||
|
categoryOptions.value = [
|
||||||
|
{ value: '1', label: '课件' },
|
||||||
|
{ value: '2', label: '教案' },
|
||||||
|
{ value: '3', label: '学案' },
|
||||||
|
{ value: '4', label: '作业' },
|
||||||
|
{ value: '5', label: '试卷' },
|
||||||
|
{ value: '6', label: '教材' },
|
||||||
|
{ value: '7', label: '示范课' },
|
||||||
|
{ value: '8', label: '音视频合集' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 返回上一页
|
||||||
|
const goBack = () => {
|
||||||
|
uni.navigateBack();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 资源目录选择
|
||||||
|
const handleResourceTypeChange = (e: any) => {
|
||||||
|
const index = e.detail.value;
|
||||||
|
const selectedItem = treeData.value[index];
|
||||||
|
formData.resourType = selectedItem.key;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 资源类别选择
|
||||||
|
const handleCategoryChange = (e: any) => {
|
||||||
|
const index = e.detail.value;
|
||||||
|
const selectedItem = categoryOptions.value[index];
|
||||||
|
formData.category = selectedItem.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加附件
|
||||||
|
const addAttachment = () => {
|
||||||
|
uni.chooseFile({
|
||||||
|
count: 5,
|
||||||
|
type: 'all',
|
||||||
|
success: async (res) => {
|
||||||
|
const tempFiles = res.tempFiles;
|
||||||
|
if (Array.isArray(tempFiles) && tempFiles.length > 0) {
|
||||||
|
uni.showLoading({ title: '上传中...' });
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (const file of tempFiles) {
|
||||||
|
const fileInfo = file as any;
|
||||||
|
let fileType = 'file';
|
||||||
|
const fileName = fileInfo.name || '';
|
||||||
|
const fileExtension = fileName.split('.').pop()?.toLowerCase();
|
||||||
|
|
||||||
|
// 根据文件扩展名判断类型
|
||||||
|
if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'].includes(fileExtension || '')) {
|
||||||
|
fileType = 'image';
|
||||||
|
} else if (['mp4', 'mov', 'avi', 'wmv', 'flv'].includes(fileExtension || '')) {
|
||||||
|
fileType = 'video';
|
||||||
|
} else if (['mp3', 'wav', 'aac', 'ogg'].includes(fileExtension || '')) {
|
||||||
|
fileType = 'audio';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据MIME类型判断
|
||||||
|
if (fileInfo.type && typeof fileInfo.type === 'string' &&
|
||||||
|
(fileInfo.type.startsWith('image/') || fileInfo.type.startsWith('video/') || fileInfo.type.startsWith('audio/'))) {
|
||||||
|
fileType = fileInfo.type.split('/')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先添加到附件列表
|
||||||
|
formData.attachments.push({
|
||||||
|
name: fileName,
|
||||||
|
type: fileType,
|
||||||
|
url: '',
|
||||||
|
size: fileInfo.size,
|
||||||
|
path: fileInfo.path,
|
||||||
|
id: Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
await uploadFile(fileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showToast({ title: '附件上传完成', icon: 'success' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('附件上传失败:', error);
|
||||||
|
uni.showToast({ title: '附件上传失败', icon: 'error' });
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('选择附件失败:', err);
|
||||||
|
if (err.errMsg && !err.errMsg.includes('cancel')) {
|
||||||
|
uni.showToast({ title: '选择附件失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除附件
|
||||||
|
const removeAttachment = (index: number) => {
|
||||||
|
formData.attachments.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 预览附件
|
||||||
|
const previewAttachment = (attachment: Attachment) => {
|
||||||
|
// 如果是图片类型,可以预览
|
||||||
|
if (attachment.type === 'image') {
|
||||||
|
const fullUrl = imagUrl(attachment.url);
|
||||||
|
uni.previewImage({
|
||||||
|
urls: [fullUrl],
|
||||||
|
current: fullUrl,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: `预览 ${attachment.name} 功能待实现`,
|
||||||
|
icon: 'none',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取附件图标
|
||||||
|
const getAttachmentIcon = (type: string): string => {
|
||||||
|
if (type === 'image') return 'image';
|
||||||
|
if (type === 'video') return 'videocam';
|
||||||
|
if (type === 'audio') return 'mic';
|
||||||
|
return 'paperclip';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
const uploadFile = async (file: any) => {
|
||||||
|
uni.showLoading({ title: '上传中...' });
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 使用 attachmentUpload 接口
|
||||||
|
const uploadResult: any = await attachmentUpload(file.path as any);
|
||||||
|
|
||||||
|
if (uploadResult.resultCode === 1 && uploadResult.result && uploadResult.result.length > 0) {
|
||||||
|
// 保存原始的 filePath(用于提交到服务器)
|
||||||
|
const originalPath = uploadResult.result[0].filePath;
|
||||||
|
const fileId = uploadResult.result[0].id;
|
||||||
|
const fileType = uploadResult.result[0].fileType;
|
||||||
|
|
||||||
|
// 更新最后一个附件的信息
|
||||||
|
const lastAttachment = formData.attachments[formData.attachments.length - 1];
|
||||||
|
if (lastAttachment) {
|
||||||
|
lastAttachment.url = originalPath;
|
||||||
|
lastAttachment.id = fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同时更新原有的文件信息(保持兼容性)
|
||||||
|
formData.fileId = fileId;
|
||||||
|
formData.filePath = originalPath;
|
||||||
|
formData.resSuf = fileType;
|
||||||
|
formData.fileName = file.name;
|
||||||
|
|
||||||
|
uni.showToast({ title: '上传成功', icon: 'success' });
|
||||||
|
} else {
|
||||||
|
throw new Error('上传失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('上传失败:', error);
|
||||||
|
uni.showToast({ title: '上传失败', icon: 'none' });
|
||||||
|
// 移除上传失败的附件
|
||||||
|
formData.attachments.pop();
|
||||||
|
} finally {
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const handleSubmitForm = async () => {
|
||||||
|
// 表单验证
|
||||||
|
if (!formData.resourName.trim()) {
|
||||||
|
uni.showToast({ title: '请输入课题名称', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formData.resourType) {
|
||||||
|
uni.showToast({ title: '请选择资源目录', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formData.hour.trim()) {
|
||||||
|
uni.showToast({ title: '请输入课时', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formData.category) {
|
||||||
|
uni.showToast({ title: '请选择资源类别', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formData.attachments.length === 0) {
|
||||||
|
uni.showToast({ title: '请上传资源文件', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSubmitting.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubmitting.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
resourName: formData.resourName,
|
||||||
|
resourType: formData.resourType,
|
||||||
|
category: formData.category,
|
||||||
|
remark: formData.content,
|
||||||
|
resourId: formData.fileId, // 保留原有的文件ID
|
||||||
|
resourUrl: formData.filePath, // 保留原有的文件路径
|
||||||
|
resSuf: formData.resSuf, // 保留原有的文件后缀
|
||||||
|
hour: formData.hour,
|
||||||
|
id: formData.id
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('提交参数:', params);
|
||||||
|
|
||||||
|
const result = await resourcesSaveApi(params);
|
||||||
|
|
||||||
|
if (result.resultCode === 1) {
|
||||||
|
uni.showToast({ title: '操作成功', icon: 'success' });
|
||||||
|
// 返回上一页并刷新列表
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateBack();
|
||||||
|
// 通过事件总线通知列表页面刷新
|
||||||
|
uni.$emit('refreshResourceList');
|
||||||
|
}, 1500);
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '操作失败', icon: 'none' });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error);
|
||||||
|
uni.showToast({ title: '操作失败,请重试', icon: 'none' });
|
||||||
|
} finally {
|
||||||
|
isSubmitting.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置表单数据
|
||||||
|
const resetFormData = () => {
|
||||||
|
formData.resourName = '';
|
||||||
|
formData.resourType = '';
|
||||||
|
formData.category = '';
|
||||||
|
formData.content = '';
|
||||||
|
formData.fileId = '';
|
||||||
|
formData.filePath = '';
|
||||||
|
formData.resSuf = '';
|
||||||
|
formData.hour = '';
|
||||||
|
formData.id = '';
|
||||||
|
formData.fileName = '';
|
||||||
|
formData.attachments = []; // 重置附件列表
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载树形数据
|
||||||
|
const loadTreeData = async () => {
|
||||||
|
try {
|
||||||
|
const res = await typesFindTreeApi();
|
||||||
|
treeData.value = res.result || [];
|
||||||
|
console.log('树形数据加载完成:', treeData.value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载树形数据失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取资源目录文本
|
||||||
|
const getResourceTypeText = () => {
|
||||||
|
const selectedItem = treeData.value.find(item => item.key === formData.resourType);
|
||||||
|
return selectedItem ? selectedItem.title : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取资源类别文本
|
||||||
|
const getCategoryText = () => {
|
||||||
|
const selectedItem = categoryOptions.value.find(item => item.value === formData.category);
|
||||||
|
return selectedItem ? selectedItem.label : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
loadTreeData();
|
||||||
|
loadCategoryOptions(); // 加载资源类别选项
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.add-resource-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f4f5f7;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 20rpx 30rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10rpx;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
width: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-scroll-view {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
padding: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
margin-bottom: 15rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.required {
|
||||||
|
color: #ff3b30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-input {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
:deep(.uni-easyinput__content) {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.uni-easyinput__content-input) {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.uni-easyinput__placeholder-class) {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachment-list {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachment-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
|
||||||
|
.attachment-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachment-name {
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #495057;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.7;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
color: #dc3545 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-attachment-placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px dashed #d5d8de;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
|
||||||
|
.add-icon {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border: 1px solid #d5d8de;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 12px;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
.uni-icons {
|
||||||
|
color: #999 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
background: white;
|
||||||
|
border-top: 1rpx solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-btn {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
background: linear-gradient(135deg, #007aff 0%, #0056cc 100%);
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 2rpx 8rpx rgba(0, 122, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-btn:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -97,10 +97,20 @@ const selectCategory = (type: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const goTo = function () {
|
const goTo = function () {
|
||||||
setData({
|
const params = {
|
||||||
resourceType: curCe.value.key,
|
resourType: curCe.value.key, // 修改参数名为resourType,与后端一致
|
||||||
category: curCategory.value.key,
|
category: curCategory.value.key,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('选择的参数:', {
|
||||||
|
科目: curType.value?.title,
|
||||||
|
年级: curNj.value?.title,
|
||||||
|
上下册: curCe.value?.title,
|
||||||
|
资源类型: curCategory.value?.label,
|
||||||
|
传递参数: params
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setData(params);
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/view/routine/JiaoXueZiYuan/indexList`
|
url: `/pages/view/routine/JiaoXueZiYuan/indexList`
|
||||||
});
|
});
|
||||||
|
|||||||
@ -88,146 +88,22 @@
|
|||||||
|
|
||||||
<!-- 底部上传按钮 -->
|
<!-- 底部上传按钮 -->
|
||||||
<template #bottom>
|
<template #bottom>
|
||||||
<view class="bottom-actions">
|
<view class="flex-row items-center pb-10 pt-5">
|
||||||
<button class="action-btn upload-btn" @click="showAddResourceModal">
|
<u-button
|
||||||
<uni-icons type="plus" size="20" color="#fff"></uni-icons>
|
text="上传资源"
|
||||||
上传资源
|
class="mx-15"
|
||||||
</button>
|
type="primary"
|
||||||
|
@click="navigateToAddResource"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</BasicListLayout>
|
</BasicListLayout>
|
||||||
|
|
||||||
<!-- 新增资源弹窗 -->
|
|
||||||
<uni-popup ref="addResourcePopup" type="center" :mask-click="false">
|
|
||||||
<view class="popup-content">
|
|
||||||
<view class="popup-header">
|
|
||||||
<text class="popup-title">{{ modalTitle }}</text>
|
|
||||||
<uni-icons type="close" size="20" color="#999" @click="closeAddResourceModal"></uni-icons>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<scroll-view scroll-y class="form-scroll-view">
|
|
||||||
<view class="form-container">
|
|
||||||
<!-- 资源目录 -->
|
|
||||||
<view class="info-card">
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="form-label">资源目录 <text class="required">*</text></text>
|
|
||||||
<picker
|
|
||||||
mode="selector"
|
|
||||||
:range="treeData"
|
|
||||||
range-key="title"
|
|
||||||
@change="handleResourceTypeChange"
|
|
||||||
>
|
|
||||||
<view class="picker-row">
|
|
||||||
<text :class="{ placeholder: !formData.resourType }">
|
|
||||||
{{ getResourceTypeText() || '请选择资源目录' }}
|
|
||||||
</text>
|
|
||||||
<uni-icons type="right" size="16" color="#999"></uni-icons>
|
|
||||||
</view>
|
|
||||||
</picker>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 课题名称 -->
|
|
||||||
<view class="info-card">
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="form-label">课题名称 <text class="required">*</text></text>
|
|
||||||
<uni-easyinput
|
|
||||||
v-model="formData.resourName"
|
|
||||||
placeholder="请输入课题名称"
|
|
||||||
:inputBorder="false"
|
|
||||||
class="content-input"
|
|
||||||
></uni-easyinput>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 课时 -->
|
|
||||||
<view class="info-card">
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="form-label">课时 <text class="required">*</text></text>
|
|
||||||
<uni-easyinput
|
|
||||||
v-model="formData.hour"
|
|
||||||
placeholder="请输入课时"
|
|
||||||
type="number"
|
|
||||||
:inputBorder="false"
|
|
||||||
class="content-input"
|
|
||||||
></uni-easyinput>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 资源类别 -->
|
|
||||||
<view class="info-card">
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="form-label">资源类别 <text class="required">*</text></text>
|
|
||||||
<picker
|
|
||||||
mode="selector"
|
|
||||||
:range="categoryOptions"
|
|
||||||
range-key="label"
|
|
||||||
@change="handleCategoryChange"
|
|
||||||
>
|
|
||||||
<view class="picker-row">
|
|
||||||
<text :class="{ placeholder: !formData.category }">
|
|
||||||
{{ getCategoryText() || '请选择资源类别' }}
|
|
||||||
</text>
|
|
||||||
<uni-icons type="right" size="16" color="#999"></uni-icons>
|
|
||||||
</view>
|
|
||||||
</picker>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 资源描述 -->
|
|
||||||
<view class="info-card">
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="form-label">资源描述</text>
|
|
||||||
<uni-easyinput
|
|
||||||
type="textarea"
|
|
||||||
autoHeight
|
|
||||||
v-model="formData.content"
|
|
||||||
placeholder="请输入资源描述"
|
|
||||||
:inputBorder="false"
|
|
||||||
class="content-input"
|
|
||||||
></uni-easyinput>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 上传资源 -->
|
|
||||||
<view class="info-card">
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="form-label">上传资源 <text class="required">*</text></text>
|
|
||||||
<view class="upload-area" @click="chooseFile">
|
|
||||||
<view v-if="!formData.filePath" class="upload-placeholder">
|
|
||||||
<uni-icons type="upload" size="40" color="#999"></uni-icons>
|
|
||||||
<text class="upload-text">点击或拖拽文件到此区域上传</text>
|
|
||||||
<text class="upload-hint">支持 .doc、.docx、.pdf、.ppt、.pptx 等格式</text>
|
|
||||||
</view>
|
|
||||||
<view v-else class="file-info">
|
|
||||||
<uni-icons type="file" size="20" color="#007aff"></uni-icons>
|
|
||||||
<text class="file-name">{{ formData.fileName }}</text>
|
|
||||||
<uni-icons type="trash" size="16" color="#ff3b30" @click="removeFile"></uni-icons>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
|
|
||||||
<!-- 弹窗底部按钮 -->
|
|
||||||
<view class="popup-bottom-actions">
|
|
||||||
<button class="action-btn cancel-btn" @click="closeAddResourceModal">
|
|
||||||
取消
|
|
||||||
</button>
|
|
||||||
<button class="action-btn confirm-btn" @click="handleSubmitForm" :disabled="isSubmitting">
|
|
||||||
{{ isSubmitting ? '提交中...' : '提交' }}
|
|
||||||
</button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</uni-popup>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { imagUrl } from "@/utils";
|
import { imagUrl } from "@/utils";
|
||||||
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
|
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
|
||||||
import { resourcesFindPageApi, resourcesAddNumByTypeApi, resourcesSaveApi } from "@/api/base/server";
|
import { resourcesFindPageApi, resourcesAddNumByTypeApi } from "@/api/base/server";
|
||||||
import { typesFindTreeApi } from "@/api/base/server";
|
|
||||||
import { useDataStore } from "@/store/modules/data";
|
import { useDataStore } from "@/store/modules/data";
|
||||||
import {
|
import {
|
||||||
isVideo,
|
isVideo,
|
||||||
@ -241,42 +117,13 @@ import {
|
|||||||
|
|
||||||
const { getData } = useDataStore();
|
const { getData } = useDataStore();
|
||||||
|
|
||||||
// 新增资源相关变量
|
|
||||||
const addResourcePopup = ref();
|
|
||||||
const modalTitle = ref('新增资源');
|
|
||||||
const isSubmitting = ref(false);
|
|
||||||
|
|
||||||
// 表单数据
|
|
||||||
const formData = reactive({
|
|
||||||
resourName: '',
|
|
||||||
resourType: '',
|
|
||||||
category: '',
|
|
||||||
content: '',
|
|
||||||
fileId: '',
|
|
||||||
filePath: '',
|
|
||||||
resSuf: '',
|
|
||||||
hour: '',
|
|
||||||
id: '',
|
|
||||||
fileName: ''
|
|
||||||
});
|
|
||||||
|
|
||||||
// 树形数据
|
|
||||||
const treeData = ref([]);
|
|
||||||
|
|
||||||
// 资源类别选项
|
|
||||||
const categoryOptions = [
|
|
||||||
{ value: '1', label: '课件' },
|
|
||||||
{ value: '2', label: '教案' },
|
|
||||||
{ value: '3', label: '学案' },
|
|
||||||
{ value: '4', label: '作业' },
|
|
||||||
{ value: '5', label: '试卷' },
|
|
||||||
{ value: '6', label: '教材' },
|
|
||||||
{ value: '7', label: '示范课' },
|
|
||||||
{ value: '8', label: '音视频合集' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const buildParams = () => {
|
const buildParams = () => {
|
||||||
setParam({ ...getData, ...{ keyword: searchKeyword.value } });
|
const params = {
|
||||||
|
...getData,
|
||||||
|
keyword: searchKeyword.value
|
||||||
|
};
|
||||||
|
console.log('查询参数:', params); // 添加调试日志
|
||||||
|
setParam(params);
|
||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,192 +238,26 @@ const downloadResouce = (item: any) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- 新增资源相关函数 ---
|
// --- 跳转到上传资源页面 ---
|
||||||
const showAddResourceModal = () => {
|
const navigateToAddResource = () => {
|
||||||
modalTitle.value = '新增资源';
|
uni.navigateTo({
|
||||||
resetFormData();
|
url: '/pages/view/routine/JiaoXueZiYuan/add-resource'
|
||||||
addResourcePopup.value.open();
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeAddResourceModal = () => {
|
|
||||||
addResourcePopup.value.close();
|
|
||||||
resetFormData();
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetFormData = () => {
|
|
||||||
formData.resourName = '';
|
|
||||||
formData.resourType = '';
|
|
||||||
formData.category = '';
|
|
||||||
formData.content = '';
|
|
||||||
formData.fileId = '';
|
|
||||||
formData.filePath = '';
|
|
||||||
formData.resSuf = '';
|
|
||||||
formData.hour = '';
|
|
||||||
formData.id = '';
|
|
||||||
formData.fileName = '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleResourceTypeChange = (e: any) => {
|
|
||||||
const index = e.detail.value;
|
|
||||||
const selectedItem = treeData.value[index];
|
|
||||||
formData.resourType = selectedItem.key;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCategoryChange = (e: any) => {
|
|
||||||
const index = e.detail.value;
|
|
||||||
const selectedItem = categoryOptions[index];
|
|
||||||
formData.category = selectedItem.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const chooseFile = () => {
|
|
||||||
uni.chooseFile({
|
|
||||||
count: 1,
|
|
||||||
type: 'all',
|
|
||||||
success: (res) => {
|
|
||||||
console.log('选择文件成功:', res);
|
|
||||||
const file = res.tempFiles[0];
|
|
||||||
formData.fileName = file.name;
|
|
||||||
formData.filePath = file.path;
|
|
||||||
formData.resSuf = file.name.split('.').pop()?.toLowerCase() || '';
|
|
||||||
|
|
||||||
// 上传文件
|
|
||||||
uploadFile(file);
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('选择文件失败:', err);
|
|
||||||
uni.showToast({ title: '选择文件失败', icon: 'none' });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const uploadFile = (file: any) => {
|
onMounted(() => {
|
||||||
uni.showLoading({ title: '上传中...' });
|
|
||||||
|
|
||||||
uni.uploadFile({
|
|
||||||
url: 'https://yufangzc.com/upload', // 替换为实际的上传地址
|
|
||||||
filePath: file.path,
|
|
||||||
name: 'files',
|
|
||||||
success: (res) => {
|
|
||||||
console.log('上传成功:', res);
|
|
||||||
const data = JSON.parse(res.data);
|
|
||||||
if (data.resultCode === 1) {
|
|
||||||
formData.fileId = data.result[0].id;
|
|
||||||
formData.filePath = data.result[0].filePath;
|
|
||||||
formData.resSuf = data.result[0].fileType;
|
|
||||||
uni.showToast({ title: '上传成功', icon: 'success' });
|
|
||||||
} else {
|
|
||||||
uni.showToast({ title: '上传失败', icon: 'none' });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('上传失败:', err);
|
|
||||||
uni.showToast({ title: '上传失败', icon: 'none' });
|
|
||||||
},
|
|
||||||
complete: () => {
|
|
||||||
uni.hideLoading();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeFile = () => {
|
|
||||||
formData.fileName = '';
|
|
||||||
formData.filePath = '';
|
|
||||||
formData.fileId = '';
|
|
||||||
formData.resSuf = '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmitForm = async () => {
|
|
||||||
// 表单验证
|
|
||||||
if (!formData.resourName.trim()) {
|
|
||||||
uni.showToast({ title: '请输入课题名称', icon: 'none' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!formData.resourType) {
|
|
||||||
uni.showToast({ title: '请选择资源目录', icon: 'none' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!formData.hour.trim()) {
|
|
||||||
uni.showToast({ title: '请输入课时', icon: 'none' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!formData.category) {
|
|
||||||
uni.showToast({ title: '请选择资源类别', icon: 'none' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!formData.filePath) {
|
|
||||||
uni.showToast({ title: '请上传资源文件', icon: 'none' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSubmitting.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isSubmitting.value = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const params = {
|
|
||||||
resourName: formData.resourName,
|
|
||||||
resourType: formData.resourType,
|
|
||||||
category: formData.category,
|
|
||||||
remark: formData.content,
|
|
||||||
resourId: formData.fileId,
|
|
||||||
resourUrl: formData.filePath,
|
|
||||||
resSuf: formData.resSuf,
|
|
||||||
hour: formData.hour,
|
|
||||||
id: formData.id
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('提交参数:', params);
|
|
||||||
|
|
||||||
const result = await resourcesSaveApi(params);
|
|
||||||
|
|
||||||
if (result.resultCode === 1) {
|
|
||||||
uni.showToast({ title: '操作成功', icon: 'success' });
|
|
||||||
closeAddResourceModal();
|
|
||||||
reload(); // 刷新列表
|
|
||||||
} else {
|
|
||||||
uni.showToast({ title: '操作失败', icon: 'none' });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('提交失败:', error);
|
|
||||||
uni.showToast({ title: '操作失败,请重试', icon: 'none' });
|
|
||||||
} finally {
|
|
||||||
isSubmitting.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 加载树形数据
|
|
||||||
const loadTreeData = async () => {
|
|
||||||
try {
|
|
||||||
const res = await typesFindTreeApi();
|
|
||||||
treeData.value = res.result || [];
|
|
||||||
console.log('树形数据加载完成:', treeData.value);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载树形数据失败:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
buildParams();
|
buildParams();
|
||||||
loadTreeData();
|
|
||||||
|
// 监听刷新列表事件
|
||||||
|
uni.$on('refreshResourceList', () => {
|
||||||
|
reload();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取资源目录文本
|
onUnmounted(() => {
|
||||||
const getResourceTypeText = () => {
|
// 移除事件监听
|
||||||
const selectedItem = treeData.value.find(item => item.key === formData.resourType);
|
uni.$off('refreshResourceList');
|
||||||
return selectedItem ? selectedItem.title : '';
|
});
|
||||||
};
|
|
||||||
|
|
||||||
// 获取资源类别文本
|
|
||||||
const getCategoryText = () => {
|
|
||||||
const selectedItem = categoryOptions.find(item => item.value === formData.category);
|
|
||||||
return selectedItem ? selectedItem.label : '';
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -769,196 +450,4 @@ const getCategoryText = () => {
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 底部上传按钮样式
|
|
||||||
.bottom-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
padding: 15px;
|
|
||||||
background: white;
|
|
||||||
border-top: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-btn {
|
|
||||||
flex: 1;
|
|
||||||
padding: 12px;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
border: none;
|
|
||||||
background: linear-gradient(135deg, #007aff 0%, #0056cc 100%);
|
|
||||||
color: white;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 122, 255, 0.3);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 弹窗样式
|
|
||||||
.popup-content {
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
width: 90vw;
|
|
||||||
max-width: 600px;
|
|
||||||
max-height: 80vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 30rpx;
|
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-title {
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-scroll-view {
|
|
||||||
flex: 1;
|
|
||||||
max-height: 60vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-container {
|
|
||||||
padding: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-card {
|
|
||||||
background: white;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
padding: 20rpx;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-item {
|
|
||||||
margin-bottom: 15rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-label {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.required {
|
|
||||||
color: #ff3b30;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-input {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
|
|
||||||
:deep(.uni-easyinput__content) {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.uni-easyinput__content-input) {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.uni-easyinput__placeholder-class) {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.picker-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20rpx 0;
|
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
|
||||||
color: #333;
|
|
||||||
font-size: 28rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-area {
|
|
||||||
border: 2rpx dashed #ddd;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
padding: 40rpx;
|
|
||||||
text-align: center;
|
|
||||||
background: #f9f9f9;
|
|
||||||
margin-top: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-placeholder {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-text {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-hint {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-name {
|
|
||||||
flex: 1;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-bottom-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 20rpx;
|
|
||||||
padding: 30rpx;
|
|
||||||
border-top: 1rpx solid #f0f0f0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cancel-btn {
|
|
||||||
flex: 1;
|
|
||||||
padding: 20rpx;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
border: none;
|
|
||||||
background: #f5f5f5;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-btn {
|
|
||||||
flex: 1;
|
|
||||||
padding: 20rpx;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
border: none;
|
|
||||||
background: linear-gradient(135deg, #007aff 0%, #0056cc 100%);
|
|
||||||
color: white;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 122, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-btn:disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
@ -9,12 +9,17 @@ import {
|
|||||||
import { AUTH_KEY } from "@/config";
|
import { AUTH_KEY } from "@/config";
|
||||||
import { useDicStore } from "@/store/modules/dic";
|
import { useDicStore } from "@/store/modules/dic";
|
||||||
import { useCommonStore } from "@/store/modules/common";
|
import { useCommonStore } from "@/store/modules/common";
|
||||||
|
import {
|
||||||
|
refreshPermissionCache,
|
||||||
|
clearPermissionCachePublic,
|
||||||
|
} from "@/utils/permission";
|
||||||
|
|
||||||
interface UserState {
|
interface UserState {
|
||||||
userdata: any;
|
userdata: any;
|
||||||
jsData: any;
|
jsData: any;
|
||||||
token: string;
|
token: string;
|
||||||
auth: string[];
|
auth: string[];
|
||||||
|
changeTime: string; // 添加权限变更时间
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUserStore = defineStore({
|
export const useUserStore = defineStore({
|
||||||
@ -28,6 +33,8 @@ export const useUserStore = defineStore({
|
|||||||
token: "",
|
token: "",
|
||||||
//用户注册信息
|
//用户注册信息
|
||||||
auth: [],
|
auth: [],
|
||||||
|
//权限变更时间
|
||||||
|
changeTime: "",
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getToken(): string {
|
getToken(): string {
|
||||||
@ -42,6 +49,9 @@ export const useUserStore = defineStore({
|
|||||||
getAuth(): string[] {
|
getAuth(): string[] {
|
||||||
return this.auth;
|
return this.auth;
|
||||||
},
|
},
|
||||||
|
getChangeTime(): string {
|
||||||
|
return this.changeTime;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setToken(token: string) {
|
setToken(token: string) {
|
||||||
@ -53,8 +63,34 @@ export const useUserStore = defineStore({
|
|||||||
setJs(data: any) {
|
setJs(data: any) {
|
||||||
this.jsData = data;
|
this.jsData = data;
|
||||||
},
|
},
|
||||||
setAuth(data: string[]) {
|
setChangeTime(changeTime: string) {
|
||||||
|
this.changeTime = changeTime;
|
||||||
|
},
|
||||||
|
setAuth(data: string[], autoRefreshCache: boolean = true) {
|
||||||
|
console.log("=== setAuth 开始 ===");
|
||||||
|
console.log("传入的权限数据:", data);
|
||||||
|
console.log("权限数量:", data ? data.length : 0);
|
||||||
|
|
||||||
|
// 检查是否与当前权限相同
|
||||||
|
if (this.auth && data) {
|
||||||
|
const isSame =
|
||||||
|
JSON.stringify(this.auth.sort()) === JSON.stringify(data.sort());
|
||||||
|
if (isSame) {
|
||||||
|
console.log("权限数据未变化,跳过更新");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("设置新的权限数据");
|
||||||
this.auth = data;
|
this.auth = data;
|
||||||
|
|
||||||
|
// 权限数据更新时,自动刷新缓存(可选)
|
||||||
|
if (autoRefreshCache && data && data.length > 0) {
|
||||||
|
console.log("自动刷新权限缓存...");
|
||||||
|
refreshPermissionCache(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("=== setAuth 完成 ===");
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @description: 验证码登录
|
* @description: 验证码登录
|
||||||
@ -67,7 +103,7 @@ export const useUserStore = defineStore({
|
|||||||
});
|
});
|
||||||
this.afterLoginAction(result);
|
this.afterLoginAction(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
// 静默处理错误
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -80,7 +116,9 @@ export const useUserStore = defineStore({
|
|||||||
password: params.password,
|
password: params.password,
|
||||||
});
|
});
|
||||||
this.afterLoginAction(result);
|
this.afterLoginAction(result);
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
// 静默处理错误
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @description: 微信登录
|
* @description: 微信登录
|
||||||
@ -90,13 +128,18 @@ export const useUserStore = defineStore({
|
|||||||
const { result } = await weChatLogin({ code: params.code });
|
const { result } = await weChatLogin({ code: params.code });
|
||||||
this.afterLoginAction(result);
|
this.afterLoginAction(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
// 静默处理错误
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async loginByOpenId(openId: string) {
|
async loginByOpenId(openId: string) {
|
||||||
try {
|
try {
|
||||||
// 先校验当前登录的用户的openid,如果和传入的openid匹配,直接返回true
|
// 先校验当前登录的用户的openid,如果和传入的openid匹配,直接返回true
|
||||||
if (this.userdata && this.userdata.openId && openId && this.userdata.openId === openId) {
|
if (
|
||||||
|
this.userdata &&
|
||||||
|
this.userdata.openId &&
|
||||||
|
openId &&
|
||||||
|
this.userdata.openId === openId
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 如果当前登录的用户的openid和传入的openid不匹配,则调用checkOpenId接口进行校验
|
// 如果当前登录的用户的openid和传入的openid不匹配,则调用checkOpenId接口进行校验
|
||||||
@ -125,21 +168,44 @@ export const useUserStore = defineStore({
|
|||||||
* @description: 登录成功后的操作
|
* @description: 登录成功后的操作
|
||||||
*/
|
*/
|
||||||
afterLoginAction(value: any) {
|
afterLoginAction(value: any) {
|
||||||
|
console.log("=== afterLoginAction 开始 ===");
|
||||||
|
console.log("用户数据:", value);
|
||||||
|
|
||||||
this.setUser(value);
|
this.setUser(value);
|
||||||
this.setJs(value.js);
|
this.setJs(value.js);
|
||||||
if (value[AUTH_KEY]) {
|
if (value[AUTH_KEY]) {
|
||||||
this.setToken(value[AUTH_KEY]);
|
this.setToken(value[AUTH_KEY]);
|
||||||
}
|
}
|
||||||
authenticationApi({ userId: value.id }).then(({ result }) => {
|
|
||||||
if (result) {
|
// 检查用户数据中是否已经包含权限信息
|
||||||
this.setAuth(result);
|
if (value.auth && Array.isArray(value.auth) && value.auth.length > 0) {
|
||||||
}
|
console.log("✅ 用户数据中包含权限信息:", value.auth);
|
||||||
});
|
console.log("权限数量:", value.auth.length);
|
||||||
|
this.setAuth(value.auth, false);
|
||||||
|
} else {
|
||||||
|
console.log("用户数据中无权限信息,调用 authenticationApi 获取权限...");
|
||||||
|
authenticationApi({ userId: value.id })
|
||||||
|
.then(({ result }) => {
|
||||||
|
if (result) {
|
||||||
|
console.log("✅ 获取到权限数据:", result);
|
||||||
|
console.log("权限数量:", result.length);
|
||||||
|
this.setAuth(result, false);
|
||||||
|
} else {
|
||||||
|
console.log("❌ authenticationApi 返回空结果");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("❌ authenticationApi 调用失败:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @description: 注销
|
* @description: 注销
|
||||||
*/
|
*/
|
||||||
logout() {
|
logout() {
|
||||||
|
// 清除权限缓存
|
||||||
|
clearPermissionCachePublic();
|
||||||
|
|
||||||
this.setToken("");
|
this.setToken("");
|
||||||
this.setUser({});
|
this.setUser({});
|
||||||
this.setJs({});
|
this.setJs({});
|
||||||
|
|||||||
@ -2,28 +2,101 @@ import {ISROUTERINTERCEPT} from "@/config";
|
|||||||
import {getRouter} from "@/utils/uniapp";
|
import {getRouter} from "@/utils/uniapp";
|
||||||
import {useUserStore} from "@/store/modules/user";
|
import {useUserStore} from "@/store/modules/user";
|
||||||
|
|
||||||
export function _auth(autd: string) {
|
// 权限缓存相关常量
|
||||||
const {getAuth} = useUserStore()
|
const PERMISSION_CACHE_KEY = 'user_permissions_cache';
|
||||||
return getAuth.includes(autd);
|
|
||||||
|
// 权限缓存接口
|
||||||
|
interface PermissionCache {
|
||||||
|
permissions: string[];
|
||||||
|
timestamp: number;
|
||||||
|
userId: string;
|
||||||
|
changeTime: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginPage(url: string) {
|
// 存储工具函数
|
||||||
uni.redirectTo({
|
function setStorage(key: string, value: any): void {
|
||||||
url: "/pages/system/login/login?redirect=" + url,
|
try {
|
||||||
});
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
const jsonValue = JSON.stringify(value);
|
||||||
|
localStorage.setItem(key, jsonValue);
|
||||||
|
} else {
|
||||||
|
uni.setStorageSync(key, value);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 静默处理错误
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStorage(key: string): any {
|
||||||
|
try {
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
const value = localStorage.getItem(key);
|
||||||
|
return value ? JSON.parse(value) : null;
|
||||||
|
} else {
|
||||||
|
const value = uni.getStorageSync(key);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从app-user中获取权限变更时间
|
||||||
|
function getChangeTimeFromAppUser(): string | null {
|
||||||
|
try {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
if (userStore.getChangeTime && userStore.getChangeTime.trim() !== '') {
|
||||||
|
return userStore.getChangeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
const appUser = localStorage.getItem('app-user');
|
||||||
|
if (appUser) {
|
||||||
|
const userData = JSON.parse(appUser);
|
||||||
|
if (userData.changeTime) {
|
||||||
|
return userData.changeTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将权限变更时间存储到app-user中
|
||||||
|
function setChangeTimeToAppUser(changeTime: string): void {
|
||||||
|
try {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
userStore.setChangeTime(changeTime);
|
||||||
|
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
const appUser = localStorage.getItem('app-user');
|
||||||
|
if (appUser) {
|
||||||
|
const userData = JSON.parse(appUser);
|
||||||
|
userData.changeTime = changeTime;
|
||||||
|
localStorage.setItem('app-user', JSON.stringify(userData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 静默处理错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路由拦截器 - 默认导出
|
||||||
export default function (whitelist: WhiteList) {
|
export default function (whitelist: WhiteList) {
|
||||||
const WHITELIST = ['/', ...whitelist, {pattern: /^\/pages\/system\/.*/}];
|
const WHITELIST = ['/', ...whitelist, {pattern: /^\/pages\/system\/.*/}];
|
||||||
const list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"];
|
const list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"];
|
||||||
// 用遍历的方式分别为,uni.navigateTo,uni.redirectTo,uni.reLaunch,uni.switchTab这4个路由方法添加拦截器
|
|
||||||
list.forEach((item) => {
|
list.forEach((item) => {
|
||||||
uni.addInterceptor(item, {
|
uni.addInterceptor(item, {
|
||||||
invoke(e) {
|
invoke(e) {
|
||||||
// 获取要跳转的页面路径(url去掉"?"和"?"后的参数)
|
// 获取要跳转的页面路径(url去掉"?"和"?"后的参数)
|
||||||
const url = e.url.split("?")[0];
|
const url = e.url.split("?")[0];
|
||||||
|
|
||||||
// 判断当前窗口是白名单,如果是则不重定向路由
|
// 判断当前窗口是白名单,如果是则不重定向路由
|
||||||
let pass;
|
let pass = false;
|
||||||
if (WHITELIST) {
|
if (WHITELIST) {
|
||||||
pass = WHITELIST.some((item) => {
|
pass = WHITELIST.some((item) => {
|
||||||
if (typeof item === "object" && item.pattern) {
|
if (typeof item === "object" && item.pattern) {
|
||||||
@ -32,6 +105,7 @@ export default function (whitelist: WhiteList) {
|
|||||||
return url === item;
|
return url === item;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 不是白名单并且没有token
|
// 不是白名单并且没有token
|
||||||
const store = useUserStore();
|
const store = useUserStore();
|
||||||
if (!pass && !store.getToken) {
|
if (!pass && !store.getToken) {
|
||||||
@ -41,15 +115,206 @@ export default function (whitelist: WhiteList) {
|
|||||||
return e;
|
return e;
|
||||||
},
|
},
|
||||||
fail(err) {
|
fail(err) {
|
||||||
// 失败回调拦截
|
// 静默处理错误
|
||||||
console.log(err);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断是否登录
|
/**
|
||||||
export function getLogin(): boolean {
|
* 获取权限缓存
|
||||||
|
*/
|
||||||
|
function getPermissionCache(): PermissionCache | null {
|
||||||
|
try {
|
||||||
|
const cacheData = getStorage(PERMISSION_CACHE_KEY);
|
||||||
|
const changeTime = getChangeTimeFromAppUser();
|
||||||
|
|
||||||
|
if (!cacheData || !changeTime) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
permissions: cacheData.permissions,
|
||||||
|
timestamp: cacheData.timestamp,
|
||||||
|
userId: cacheData.userId,
|
||||||
|
changeTime: cacheData.changeTime
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置权限缓存
|
||||||
|
* @param permissions 权限列表
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param changeTime 权限变更时间(可选)
|
||||||
|
*/
|
||||||
|
function setPermissionCache(permissions: string[], userId: string, changeTime?: string): void {
|
||||||
|
try {
|
||||||
|
const defaultChangeTime = '2024-01-01 00:00:00';
|
||||||
|
const finalChangeTime = changeTime || defaultChangeTime;
|
||||||
|
|
||||||
|
const cacheData: PermissionCache = {
|
||||||
|
permissions,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
userId,
|
||||||
|
changeTime: finalChangeTime
|
||||||
|
};
|
||||||
|
|
||||||
|
setStorage(PERMISSION_CACHE_KEY, cacheData);
|
||||||
|
setChangeTimeToAppUser(finalChangeTime);
|
||||||
|
} catch (error) {
|
||||||
|
// 静默处理错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除权限缓存
|
||||||
|
*/
|
||||||
|
function clearPermissionCache(): void {
|
||||||
|
try {
|
||||||
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
localStorage.removeItem(PERMISSION_CACHE_KEY);
|
||||||
|
} else {
|
||||||
|
uni.removeStorageSync(PERMISSION_CACHE_KEY);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 静默处理错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证缓存是否有效
|
||||||
|
*/
|
||||||
|
function isCacheValid(cache: PermissionCache, currentUserId: string): boolean {
|
||||||
|
return cache.userId === currentUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户权限列表(带缓存)
|
||||||
|
* @param currentChangeTime 当前服务器返回的权限变更时间
|
||||||
|
* @returns 权限列表
|
||||||
|
*/
|
||||||
|
function getUserPermissionsWithCache(currentChangeTime?: string): string[] {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const currentUser = userStore.getUser;
|
||||||
|
const currentUserId = currentUser?.id || currentUser?.userdata?.id;
|
||||||
|
|
||||||
|
if (!currentUserId) {
|
||||||
|
return userStore.getAuth;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cache = getPermissionCache();
|
||||||
|
if (cache && isCacheValid(cache, currentUserId)) {
|
||||||
|
if (currentChangeTime) {
|
||||||
|
const serverTime = new Date(currentChangeTime).getTime();
|
||||||
|
const cacheTime = new Date(cache.changeTime).getTime();
|
||||||
|
|
||||||
|
if (serverTime > cacheTime) {
|
||||||
|
const permissions = userStore.getAuth;
|
||||||
|
if (permissions && permissions.length > 0) {
|
||||||
|
setPermissionCache(permissions, currentUserId, currentChangeTime);
|
||||||
|
}
|
||||||
|
return permissions;
|
||||||
|
} else {
|
||||||
|
return cache.permissions;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return cache.permissions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissions = userStore.getAuth;
|
||||||
|
if (permissions && permissions.length > 0) {
|
||||||
|
setPermissionCache(permissions, currentUserId, currentChangeTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新权限缓存
|
||||||
|
* @param permissions 新的权限列表
|
||||||
|
* @param changeTime 权限变更时间(可选)
|
||||||
|
*/
|
||||||
|
export function refreshPermissionCache(permissions?: string[], changeTime?: string): void {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const currentUser = userStore.getUser;
|
||||||
|
const currentUserId = currentUser?.id || currentUser?.userdata?.id;
|
||||||
|
|
||||||
|
if (!currentUserId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissionList = permissions || userStore.getAuth;
|
||||||
|
|
||||||
|
const currentCache = getPermissionCache();
|
||||||
|
if (currentCache && currentCache.permissions && permissionList) {
|
||||||
|
const isSame = JSON.stringify(currentCache.permissions.sort()) === JSON.stringify(permissionList.sort());
|
||||||
|
if (isSame && currentCache.changeTime === changeTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setPermissionCache(permissionList, currentUserId, changeTime);
|
||||||
|
|
||||||
|
if (changeTime) {
|
||||||
|
userStore.setChangeTime(changeTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除权限缓存(供外部调用)
|
||||||
|
*/
|
||||||
|
export function clearPermissionCachePublic(): void {
|
||||||
|
clearPermissionCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 权限检查函数
|
||||||
|
export function _auth(autd: string, changeTime?: string) {
|
||||||
|
const permissions = getUserPermissionsWithCache(changeTime);
|
||||||
|
return permissions.includes(autd);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasPermission(permissionKey: string, changeTime?: string): boolean {
|
||||||
|
if (!permissionKey) return true;
|
||||||
|
const permissions = getUserPermissionsWithCache(changeTime);
|
||||||
|
// 去重处理,避免重复权限影响判断
|
||||||
|
const uniquePermissions = [...new Set(permissions)];
|
||||||
|
return uniquePermissions.includes(permissionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasAnyPermission(permissionKeys: string[], changeTime?: string): boolean {
|
||||||
|
if (!permissionKeys || permissionKeys.length === 0) return true;
|
||||||
|
const permissions = getUserPermissionsWithCache(changeTime);
|
||||||
|
// 去重处理,避免重复权限影响判断
|
||||||
|
const uniquePermissions = [...new Set(permissions)];
|
||||||
|
return permissionKeys.some(key => uniquePermissions.includes(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasAllPermissions(permissionKeys: string[], changeTime?: string): boolean {
|
||||||
|
if (!permissionKeys || permissionKeys.length === 0) return true;
|
||||||
|
const permissions = getUserPermissionsWithCache(changeTime);
|
||||||
|
// 去重处理,避免重复权限影响判断
|
||||||
|
const uniquePermissions = [...new Set(permissions)];
|
||||||
|
return permissionKeys.every(key => uniquePermissions.includes(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserPermissions(changeTime?: string): string[] {
|
||||||
|
const permissions = getUserPermissionsWithCache(changeTime);
|
||||||
|
// 返回去重后的权限列表
|
||||||
|
return permissions ? [...new Set(permissions)] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLogin(): void {
|
||||||
|
clearPermissionCache();
|
||||||
|
uni.reLaunch({
|
||||||
|
url: "/pages/system/login/login",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLogin(): boolean {
|
||||||
if (ISROUTERINTERCEPT) {
|
if (ISROUTERINTERCEPT) {
|
||||||
const store = useUserStore();
|
const store = useUserStore();
|
||||||
if (!store.getToken) {
|
if (!store.getToken) {
|
||||||
@ -66,3 +331,71 @@ export function getLogin(): boolean {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loginPage(url: string) {
|
||||||
|
uni.redirectTo({
|
||||||
|
url: "/pages/system/login/login?redirect=" + url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ROUTINE_PERMISSIONS = {
|
||||||
|
JIAO_XUE_ZI_YUAN: 'JiaoXueZiYuan',
|
||||||
|
JI_FEN_PING_JIA: 'JiFenPingJia',
|
||||||
|
GONG_ZUO_LIANG: 'GongZuoLiang',
|
||||||
|
RENG_JIAO_RENG_ZHI: 'RengJiaoRengZhi',
|
||||||
|
SHI_TANG_XUN_CHA: 'ShiTangXunCha',
|
||||||
|
KE_FU_XUN_CHA: 'kefuxuncha',
|
||||||
|
GROUP_TEACHING: 'groupTeaching',
|
||||||
|
NOTICE: 'notice',
|
||||||
|
ROUTINE: 'routine',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export function isTeacherUser(): boolean {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const user = userStore.getUser;
|
||||||
|
return user && user.userType === 'teacher';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAdminUser(): boolean {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const user = userStore.getUser;
|
||||||
|
return user && user.userType === 'admin';
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PermissionCacheManager = {
|
||||||
|
getCacheInfo() {
|
||||||
|
const cache = getPermissionCache();
|
||||||
|
const changeTime = getChangeTimeFromAppUser();
|
||||||
|
|
||||||
|
return {
|
||||||
|
hasCache: !!cache,
|
||||||
|
changeTime: changeTime ? new Date(changeTime).toLocaleString() : null,
|
||||||
|
isExpired: cache ? Date.now() > cache.timestamp : true,
|
||||||
|
cacheSize: cache ? cache.permissions.length : 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示详细的缓存信息(调试用)
|
||||||
|
*/
|
||||||
|
debugCache() {
|
||||||
|
// 移除所有调试信息
|
||||||
|
},
|
||||||
|
|
||||||
|
forceRefresh() {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const permissions = userStore.getAuth;
|
||||||
|
const currentUser = userStore.getUser;
|
||||||
|
const currentUserId = currentUser?.id || currentUser?.userdata?.id;
|
||||||
|
|
||||||
|
if (currentUserId && permissions) {
|
||||||
|
setPermissionCache(permissions, currentUserId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
clearPermissionCache();
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user