Merge pull request #7 from PlayEdu/dev

Dev
This commit is contained in:
Teng 2023-06-13 14:10:48 +08:00 committed by GitHub
commit 7dc58e2fde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 792 additions and 158 deletions

View File

@ -8,9 +8,15 @@
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
/> />
<title>管理后台</title> <title>管理后台</title>
<script src="/js/DPlayer.min.js"></script>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script type="module" src="/src/main.tsx"></script> <script type="module" src="/src/main.tsx"></script>
<script
crossorigin="anonymous"
integrity="sha512-oHrfR/z2wkuRuaHrdZ9NhoT/o/1kteub+QvmQgVzOKK7NTvIKQMvnY9+/RR0+eW311o4lAE/YzzLXXmP2XUvig=="
src="https://lib.baomitu.com/hls.js/1.1.4/hls.min.js"
></script>
</body> </body>
</html> </html>

1
public/js/DPlayer.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/js/xg/hls.min.js vendored Normal file

File diff suppressed because one or more lines are too long

21
public/js/xg/index.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -61,3 +61,11 @@ export function destroyResourceMulti(ids: number[]) {
ids: ids, ids: ids,
}); });
} }
export function videoDetail(id: number) {
return client.get(`/backend/v1/resource/${id}`, {});
}
export function videoUpdate(id: number, params: any) {
return client.put(`/backend/v1/resource/${id}`, params);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

View File

@ -1,16 +1,25 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Menu } from "antd"; import { Menu } from "antd";
import { useSelector } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useLocation } from "react-router-dom";
import styles from "./index.module.less"; import styles from "./index.module.less";
import logo from "../../assets/logo.png"; import logo from "../../assets/logo.png";
function getItem(label: any, key: any, icon: any, children: any, type: any) { function getItem(
label: any,
key: any,
icon: any,
children: any,
type: any,
permission: any
) {
return { return {
key, key,
icon, icon,
children, children,
label, label,
type, type,
permission,
}; };
} }
const items = [ const items = [
@ -19,6 +28,7 @@ const items = [
"/", "/",
<i className={`iconfont icon-icon-home`} />, <i className={`iconfont icon-icon-home`} />,
null, null,
null,
null null
), ),
getItem( getItem(
@ -26,6 +36,7 @@ const items = [
"/resource-category", "/resource-category",
<i className="iconfont icon-icon-category" />, <i className="iconfont icon-icon-category" />,
null, null,
null,
null null
), ),
getItem( getItem(
@ -33,16 +44,18 @@ const items = [
"resource", "resource",
<i className="iconfont icon-icon-file" />, <i className="iconfont icon-icon-file" />,
[ [
getItem("视频", "/videos", null, null, null), getItem("视频", "/videos", null, null, null, null),
getItem("图片", "/images", null, null, null), getItem("图片", "/images", null, null, null, null),
], ],
null,
null null
), ),
getItem( getItem(
"课程中心", "课程中心",
"courses", "courses",
<i className="iconfont icon-icon-study" />, <i className="iconfont icon-icon-study" />,
[getItem("线上课", "/course", null, null, null)], [getItem("线上课", "/course", null, null, null, "course")],
null,
null null
), ),
getItem( getItem(
@ -50,9 +63,10 @@ const items = [
"user", "user",
<i className="iconfont icon-icon-user" />, <i className="iconfont icon-icon-user" />,
[ [
getItem("学员", "/member/index", null, null, null), getItem("学员", "/member/index", null, null, null, "user-index"),
getItem("部门", "/department", null, null, null), getItem("部门", "/department", null, null, null, "department-cud"),
], ],
null,
null null
), ),
getItem( getItem(
@ -60,14 +74,32 @@ const items = [
"system", "system",
<i className="iconfont icon-icon-setting" />, <i className="iconfont icon-icon-setting" />,
[ [
getItem("系统配置", "/system/config/index", null, null, null), getItem(
getItem("管理人员", "/system/administrator", null, null, null), "系统配置",
// getItem("角色配置", "/system/adminroles", null, null, null), "/system/config/index",
null,
null,
null,
"system-config"
),
getItem(
"管理人员",
"/system/administrator",
null,
null,
null,
"admin-user-index"
),
// getItem("角色配置", "/system/adminroles", null, null, null, null),
], ],
null,
null null
), ),
]; ];
export const LeftMenu: React.FC = () => {
const location = useLocation();
const navigate = useNavigate();
const children2Parent: any = { const children2Parent: any = {
"^/video": ["resource"], "^/video": ["resource"],
"^/image": ["resource"], "^/image": ["resource"],
@ -77,10 +109,6 @@ const children2Parent: any = {
"^/system": ["system"], "^/system": ["system"],
}; };
export const LeftMenu: React.FC = () => {
const location = useLocation();
const navigate = useNavigate();
const hit = (pathname: string): string[] => { const hit = (pathname: string): string[] => {
for (let p in children2Parent) { for (let p in children2Parent) {
if (pathname.search(p) >= 0) { if (pathname.search(p) >= 0) {
@ -104,7 +132,6 @@ export const LeftMenu: React.FC = () => {
} }
newOpenKeys.push(openKeys[i]); newOpenKeys.push(openKeys[i]);
} }
return newOpenKeys; return newOpenKeys;
}; };
@ -114,11 +141,54 @@ export const LeftMenu: React.FC = () => {
]); ]);
// 展开菜单 // 展开菜单
const [openKeys, setOpenKeys] = useState<string[]>(hit(location.pathname)); const [openKeys, setOpenKeys] = useState<string[]>(hit(location.pathname));
const permissions = useSelector(
(state: any) => state.loginUser.value.permissions
);
const [activeMenus, setActiveMenus] = useState<any>([]);
const onClick = (e: any) => { const onClick = (e: any) => {
navigate(e.key); navigate(e.key);
}; };
useEffect(() => {
checkMenuPermissions(items, permissions);
}, [items, permissions]);
const checkMenuPermissions = (items: any, permissions: any) => {
let menus: any = [];
if (permissions.length === 0) {
setActiveMenus(menus);
return;
}
for (let i in items) {
let menuItem = items[i];
if (!menuItem.children) {
// 一级菜单不做权限控制
menus.push(menuItem);
continue;
}
let children = [];
for (let j in menuItem.children) {
let childrenItem = menuItem.children[j];
if (
typeof permissions[childrenItem.permission] !== "undefined" ||
!childrenItem.permission
) {
// 存在权限
children.push(childrenItem);
}
}
if (children.length > 0) {
menus.push(Object.assign({}, menuItem, { children: children }));
}
}
setActiveMenus(menus);
};
useEffect(() => { useEffect(() => {
if (location.pathname.indexOf("/course/user") !== -1) { if (location.pathname.indexOf("/course/user") !== -1) {
setSelectedKeys(["/course"]); setSelectedKeys(["/course"]);
@ -159,7 +229,7 @@ export const LeftMenu: React.FC = () => {
selectedKeys={selectedKeys} selectedKeys={selectedKeys}
openKeys={openKeys} openKeys={openKeys}
mode="inline" mode="inline"
items={items} items={activeMenus}
onSelect={(data: any) => { onSelect={(data: any) => {
setSelectedKeys(data.selectedKeys); setSelectedKeys(data.selectedKeys);
}} }}

View File

@ -13,13 +13,14 @@ interface PropInterface {
roleDelSuccess: boolean; roleDelSuccess: boolean;
type: string; type: string;
text: string; text: string;
onUpdate: (keys: any, title: any) => void; onUpdate: (keys: any, title: any, isSuper: boolean) => void;
} }
export const TreeAdminroles = (props: PropInterface) => { export const TreeAdminroles = (props: PropInterface) => {
const [treeData, setTreeData] = useState<any>([]); const [treeData, setTreeData] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [selectKey, setSelectKey] = useState<any>([]); const [selectKey, setSelectKey] = useState<any>([]);
const [superId, setSuperId] = useState(0);
useEffect(() => { useEffect(() => {
onSelect([], ""); onSelect([], "");
@ -28,6 +29,7 @@ export const TreeAdminroles = (props: PropInterface) => {
useEffect(() => { useEffect(() => {
adminRole.adminRoleList().then((res: any) => { adminRole.adminRoleList().then((res: any) => {
let adminrole = res.data; let adminrole = res.data;
let superId = 0;
if (adminrole.length > 0) { if (adminrole.length > 0) {
const new_arr: Option[] = []; const new_arr: Option[] = [];
for (let i = 0; i < adminrole.length; i++) { for (let i = 0; i < adminrole.length; i++) {
@ -36,9 +38,13 @@ export const TreeAdminroles = (props: PropInterface) => {
key: adminrole[i].id, key: adminrole[i].id,
children: [], children: [],
}); });
if (adminrole[i].slug === "super-role") {
superId = adminrole[i].id;
}
} }
setTreeData(new_arr); setTreeData(new_arr);
} }
setSuperId(superId);
}); });
}, [props.refresh]); }, [props.refresh]);
@ -47,7 +53,11 @@ export const TreeAdminroles = (props: PropInterface) => {
if (info) { if (info) {
label = info.node.title; label = info.node.title;
} }
props.onUpdate(selectedKeys, label); let isSuper = false;
if (selectedKeys[0] === superId && superId !== 0) {
isSuper = true;
}
props.onUpdate(selectedKeys, label, isSuper);
setSelectKey(selectedKeys); setSelectKey(selectedKeys);
}; };

View File

@ -5,13 +5,13 @@ import { resourceCategory } from "../../api/index";
interface Option { interface Option {
key: string | number; key: string | number;
title: any; title: any;
children?: Option[]; children?: Option[];
} }
interface PropInterface { interface PropInterface {
type: string; type: string;
text: string; text: string;
selected: any;
onUpdate: (keys: any, title: any) => void; onUpdate: (keys: any, title: any) => void;
} }
@ -20,6 +20,12 @@ export const TreeCategory = (props: PropInterface) => {
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [selectKey, setSelectKey] = useState<any>([]); const [selectKey, setSelectKey] = useState<any>([]);
useEffect(() => {
if (props.selected && props.selected.length > 0) {
setSelectKey(props.selected);
}
}, [props.selected]);
useEffect(() => { useEffect(() => {
resourceCategory.resourceCategoryList().then((res: any) => { resourceCategory.resourceCategoryList().then((res: any) => {
const categories = res.data.categories; const categories = res.data.categories;

View File

@ -13,6 +13,7 @@ interface PropInterface {
text: string; text: string;
refresh: boolean; refresh: boolean;
showNum: boolean; showNum: boolean;
selected: any;
onUpdate: (keys: any, title: any) => void; onUpdate: (keys: any, title: any) => void;
} }
@ -22,6 +23,12 @@ export const TreeDepartment = (props: PropInterface) => {
const [selectKey, setSelectKey] = useState<any>([]); const [selectKey, setSelectKey] = useState<any>([]);
const [userTotal, setUserTotal] = useState(0); const [userTotal, setUserTotal] = useState(0);
useEffect(() => {
if (props.selected && props.selected.length > 0) {
setSelectKey(props.selected);
}
}, [props.selected]);
useEffect(() => { useEffect(() => {
setLoading(true); setLoading(true);
department.departmentList().then((res: any) => { department.departmentList().then((res: any) => {

View File

@ -110,6 +110,7 @@ export const UploadImageButton = (props: PropsInterface) => {
<Row style={{ width: 752, minHeight: 520, marginTop: 24 }}> <Row style={{ width: 752, minHeight: 520, marginTop: 24 }}>
<Col span={7}> <Col span={7}>
<TreeCategory <TreeCategory
selected={category_ids}
type="no-cate" type="no-cate"
text={"图片"} text={"图片"}
onUpdate={(keys: any) => { onUpdate={(keys: any) => {

View File

@ -2,7 +2,7 @@ import { Button, message, Modal } from "antd";
import Dragger from "antd/es/upload/Dragger"; import Dragger from "antd/es/upload/Dragger";
import { useState } from "react"; import { useState } from "react";
import config from "../../../js/config"; import config from "../../../js/config";
import { getToken } from "../../../utils"; import { getToken, checkUrl } from "../../../utils";
import { InboxOutlined } from "@ant-design/icons"; import { InboxOutlined } from "@ant-design/icons";
interface PropsInterface { interface PropsInterface {
@ -17,8 +17,8 @@ export const UploadImageSub = (props: PropsInterface) => {
name: "file", name: "file",
multiple: true, multiple: true,
action: action:
config.app_url + checkUrl(config.app_url) +
"/backend/v1/upload/minio?category_ids=" + "backend/v1/upload/minio?category_ids=" +
props.categoryIds.join(","), props.categoryIds.join(","),
headers: { headers: {
authorization: "Bearer " + getToken(), authorization: "Bearer " + getToken(),

View File

@ -173,6 +173,7 @@ export const UploadVideoSub = (props: PropsInterface) => {
<Row style={{ width: 752, minHeight: 520 }}> <Row style={{ width: 752, minHeight: 520 }}>
<Col span={7}> <Col span={7}>
<TreeCategory <TreeCategory
selected={[]}
type="no-cate" type="no-cate"
text={props.label} text={props.label}
onUpdate={(keys: any) => setCategoryIds(keys)} onUpdate={(keys: any) => setCategoryIds(keys)}

View File

@ -519,16 +519,27 @@ textarea.ant-input {
position: relative; position: relative;
} }
.ant-modal-confirm-btns > .ant-btn-default:hover { .ant-modal-confirm-btns > .ant-btn-default {
outline: none;
box-shadow: none !important;
&:hover {
box-shadow: none !important;
color: #ff4d4f !important; color: #ff4d4f !important;
border-color: #ff4d4f; border-color: #ff4d4f;
outline: none;
}
} }
.ant-modal-confirm-btns > .ant-btn-primary { .ant-modal-confirm-btns > .ant-btn-primary {
border: none;
box-shadow: none !important;
background-color: #ff4d4f !important; background-color: #ff4d4f !important;
color: #fff; color: #fff;
outline: none;
&:hover { &:hover {
box-shadow: none !important;
opacity: 0.8; opacity: 0.8;
outline: none;
} }
} }
.ant-tree-treenode { .ant-tree-treenode {

View File

@ -482,9 +482,9 @@ export const CourseCreate: React.FC<PropInterface> = ({
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="必修选修" label="课程属性"
name="isRequired" name="isRequired"
rules={[{ required: true, message: "请选择必修选修!" }]} rules={[{ required: true, message: "请选择课程属性!" }]}
> >
<Radio.Group> <Radio.Group>
<Radio value={1}></Radio> <Radio value={1}></Radio>

View File

@ -230,9 +230,9 @@ export const CourseUpdate: React.FC<PropInterface> = ({
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="必修选修" label="课程属性"
name="isRequired" name="isRequired"
rules={[{ required: true, message: "请选择必修选修!" }]} rules={[{ required: true, message: "请选择课程属性!" }]}
> >
<Radio.Group> <Radio.Group>
<Radio value={1}></Radio> <Radio value={1}></Radio>

View File

@ -21,7 +21,7 @@ import {
import type { MenuProps } from "antd"; import type { MenuProps } from "antd";
import type { ColumnsType } from "antd/es/table"; import type { ColumnsType } from "antd/es/table";
import { dateFormat } from "../../utils/index"; import { dateFormat } from "../../utils/index";
import { useNavigate } from "react-router-dom"; import { useNavigate, useLocation } from "react-router-dom";
import { TreeDepartment, TreeCategory, PerButton } from "../../compenents"; import { TreeDepartment, TreeCategory, PerButton } from "../../compenents";
import type { TabsProps } from "antd"; import type { TabsProps } from "antd";
import { CourseCreate } from "./compenents/create"; import { CourseCreate } from "./compenents/create";
@ -40,6 +40,7 @@ interface DataType {
} }
const CoursePage = () => { const CoursePage = () => {
const result = new URLSearchParams(useLocation().search);
const navigate = useNavigate(); const navigate = useNavigate();
const [list, setList] = useState<any>([]); const [list, setList] = useState<any>([]);
const [refresh, setRefresh] = useState(false); const [refresh, setRefresh] = useState(false);
@ -50,18 +51,43 @@ const CoursePage = () => {
const [category_ids, setCategoryIds] = useState<any>([]); const [category_ids, setCategoryIds] = useState<any>([]);
const [title, setTitle] = useState<string>(""); const [title, setTitle] = useState<string>("");
const [dep_ids, setDepIds] = useState<any>([]); const [dep_ids, setDepIds] = useState<any>([]);
const [selLabel, setLabel] = useState<string>("全部分类"); const [selLabel, setLabel] = useState<string>(
const [selDepLabel, setDepLabel] = useState<string>("全部部门"); result.get("label") ? String(result.get("label")) : "全部分类"
);
const [selDepLabel, setDepLabel] = useState<string>(
result.get("label") ? String(result.get("label")) : "全部部门"
);
const [course_category_ids, setCourseCategoryIds] = useState<any>({}); const [course_category_ids, setCourseCategoryIds] = useState<any>({});
const [course_dep_ids, setCourseDepIds] = useState<any>({}); const [course_dep_ids, setCourseDepIds] = useState<any>({});
const [categories, setCategories] = useState<any>({}); const [categories, setCategories] = useState<any>({});
const [departments, setDepartments] = useState<any>({}); const [departments, setDepartments] = useState<any>({});
const [tabKey, setTabKey] = useState(1); const [tabKey, setTabKey] = useState(result.get("did") ? "2" : "1");
const [createVisible, setCreateVisible] = useState<boolean>(false); const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false); const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const [updateHourVisible, setHourUpdateVisible] = useState<boolean>(false); const [updateHourVisible, setHourUpdateVisible] = useState<boolean>(false);
const [cid, setCid] = useState<number>(0); const [cid, setCid] = useState<number>(0);
const [cateId, setCateId] = useState(Number(result.get("cid")));
const [did, setDid] = useState(Number(result.get("did")));
useEffect(() => {
getList();
}, [category_ids, dep_ids, refresh, page, size, tabKey]);
useEffect(() => {
setCateId(Number(result.get("cid")));
if (Number(result.get("cid"))) {
let arr = [];
arr.push(Number(result.get("cid")));
setCategoryIds(arr);
}
setDid(Number(result.get("did")));
if (Number(result.get("did"))) {
let arr = [];
arr.push(Number(result.get("did")));
setDepIds(arr);
}
}, [result.get("cid"), result.get("did")]);
const items: TabsProps["items"] = [ const items: TabsProps["items"] = [
{ {
@ -70,9 +96,11 @@ const CoursePage = () => {
children: ( children: (
<div className="float-left"> <div className="float-left">
<TreeCategory <TreeCategory
selected={category_ids}
type="" type=""
text={"分类"} text={"分类"}
onUpdate={(keys: any, title: any) => { onUpdate={(keys: any, title: any) => {
setPage(1);
setCategoryIds(keys); setCategoryIds(keys);
if (typeof title === "string") { if (typeof title === "string") {
setLabel(title); setLabel(title);
@ -90,11 +118,13 @@ const CoursePage = () => {
children: ( children: (
<div className="float-left"> <div className="float-left">
<TreeDepartment <TreeDepartment
selected={dep_ids}
refresh={refresh} refresh={refresh}
showNum={false} showNum={false}
type="no-course" type="no-course"
text={"部门"} text={"部门"}
onUpdate={(keys: any, title: any) => { onUpdate={(keys: any, title: any) => {
setPage(1);
setDepIds(keys); setDepIds(keys);
setDepLabel(title); setDepLabel(title);
}} }}
@ -288,7 +318,7 @@ const CoursePage = () => {
setLoading(true); setLoading(true);
let categoryIds = ""; let categoryIds = "";
let depIds = ""; let depIds = "";
if (tabKey === 1) { if (tabKey === "1") {
categoryIds = category_ids.join(","); categoryIds = category_ids.join(",");
} else { } else {
depIds = dep_ids.join(","); depIds = dep_ids.join(",");
@ -317,11 +347,6 @@ const CoursePage = () => {
setRefresh(!refresh); setRefresh(!refresh);
}; };
// 加载列表
useEffect(() => {
getList();
}, [category_ids, dep_ids, refresh, page, size, tabKey]);
const paginationProps = { const paginationProps = {
current: page, //当前页码 current: page, //当前页码
pageSize: size, pageSize: size,
@ -337,7 +362,7 @@ const CoursePage = () => {
}; };
const onChange = (key: string) => { const onChange = (key: string) => {
setTabKey(Number(key)); setTabKey(key);
}; };
return ( return (
@ -345,7 +370,7 @@ const CoursePage = () => {
<div className="tree-main-body"> <div className="tree-main-body">
<div className="left-box"> <div className="left-box">
<Tabs <Tabs
defaultActiveKey="1" defaultActiveKey={tabKey}
centered centered
tabBarGutter={55} tabBarGutter={55}
items={items} items={items}
@ -354,7 +379,7 @@ const CoursePage = () => {
</div> </div>
<div className="right-box"> <div className="right-box">
<div className="playedu-main-title float-left mb-24"> <div className="playedu-main-title float-left mb-24">
线 | {tabKey === 1 ? selLabel : selDepLabel} 线 | {tabKey === "1" ? selLabel : selDepLabel}
</div> </div>
<div className="float-left j-b-flex mb-24"> <div className="float-left j-b-flex mb-24">
<div className="d-flex"> <div className="d-flex">
@ -406,8 +431,8 @@ const CoursePage = () => {
rowKey={(record) => record.id} rowKey={(record) => record.id}
/> />
<CourseCreate <CourseCreate
cateIds={tabKey === 1 ? category_ids : []} cateIds={tabKey === "1" ? category_ids : []}
depIds={tabKey === 2 ? dep_ids : []} depIds={tabKey === "2" ? dep_ids : []}
open={createVisible} open={createVisible}
onCancel={() => { onCancel={() => {
setCreateVisible(false); setCreateVisible(false);

View File

@ -89,7 +89,12 @@ const DepartmentPage = () => {
<i <i
className="iconfont icon-icon-delete" className="iconfont icon-icon-delete"
style={{ fontSize: 24 }} style={{ fontSize: 24 }}
onClick={() => removeItem(departments[id][i].id)} onClick={() =>
removeItem(
departments[id][i].id,
departments[id][i].name
)
}
/> />
</> </>
)} )}
@ -124,7 +129,12 @@ const DepartmentPage = () => {
<i <i
className="iconfont icon-icon-delete" className="iconfont icon-icon-delete"
style={{ fontSize: 24 }} style={{ fontSize: 24 }}
onClick={() => removeItem(departments[id][i].id)} onClick={() =>
removeItem(
departments[id][i].id,
departments[id][i].name
)
}
/> />
</> </>
)} )}
@ -144,19 +154,22 @@ const DepartmentPage = () => {
setRefresh(!refresh); setRefresh(!refresh);
}; };
const removeItem = (id: number) => { const removeItem = (id: number, label: string) => {
if (id === 0) { if (id === 0) {
return; return;
} }
department.checkDestroy(id).then((res: any) => { department.checkDestroy(id).then((res: any) => {
if ( if (
res.data.children &&
res.data.children.length === 0 && res.data.children.length === 0 &&
res.data.courses &&
res.data.courses.length === 0 && res.data.courses.length === 0 &&
res.data.users &&
res.data.users.length === 0 res.data.users.length === 0
) { ) {
delUser(id); delUser(id);
} else { } else {
if (res.data.children.length > 0) { if (res.data.children && res.data.children.length > 0) {
modal.warning({ modal.warning({
title: "操作确认", title: "操作确认",
centered: true, centered: true,
@ -179,22 +192,26 @@ const DepartmentPage = () => {
content: ( content: (
<p> <p>
{res.data.courses.length > 0 && ( {res.data.courses && res.data.courses.length > 0 && (
<Button <Button
style={{ paddingLeft: 4, paddingRight: 4 }} style={{ paddingLeft: 4, paddingRight: 4 }}
type="link" type="link"
danger danger
onClick={() => navigate("/course")} onClick={() =>
navigate("/course?did=" + id + "&label=" + label)
}
> >
{res.data.courses.length}线 {res.data.courses.length}线
</Button> </Button>
)} )}
{res.data.users.length > 0 && ( {res.data.users && res.data.users.length > 0 && (
<Button <Button
type="link" type="link"
style={{ paddingLeft: 4, paddingRight: 4 }} style={{ paddingLeft: 4, paddingRight: 4 }}
danger danger
onClick={() => navigate("/member/index")} onClick={() =>
navigate("/member/index?did=" + id + "&label=" + label)
}
> >
{res.data.users.length} {res.data.users.length}
</Button> </Button>

View File

@ -20,7 +20,7 @@ import {
} from "@ant-design/icons"; } from "@ant-design/icons";
import { user } from "../../api/index"; import { user } from "../../api/index";
import { dateFormat } from "../../utils/index"; import { dateFormat } from "../../utils/index";
import { Link, Navigate } from "react-router-dom"; import { Link, Navigate, useLocation } from "react-router-dom";
import { TreeDepartment, PerButton } from "../../compenents"; import { TreeDepartment, PerButton } from "../../compenents";
import { MemberCreate } from "./compenents/create"; import { MemberCreate } from "./compenents/create";
import { MemberUpdate } from "./compenents/update"; import { MemberUpdate } from "./compenents/update";
@ -37,6 +37,7 @@ interface DataType {
} }
const MemberPage = () => { const MemberPage = () => {
const result = new URLSearchParams(useLocation().search);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [size, setSize] = useState(10); const [size, setSize] = useState(10);
@ -47,12 +48,24 @@ const MemberPage = () => {
const [nickname, setNickname] = useState<string>(""); const [nickname, setNickname] = useState<string>("");
const [email, setEmail] = useState<string>(""); const [email, setEmail] = useState<string>("");
const [dep_ids, setDepIds] = useState<any>([]); const [dep_ids, setDepIds] = useState<any>([]);
const [selLabel, setLabel] = useState<string>("全部部门"); const [selLabel, setLabel] = useState<string>(
result.get("label") ? String(result.get("label")) : "全部部门"
);
const [createVisible, setCreateVisible] = useState<boolean>(false); const [createVisible, setCreateVisible] = useState<boolean>(false);
const [updateVisible, setUpdateVisible] = useState<boolean>(false); const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const [mid, setMid] = useState<number>(0); const [mid, setMid] = useState<number>(0);
const [user_dep_ids, setUserDepIds] = useState<any>({}); const [user_dep_ids, setUserDepIds] = useState<any>({});
const [departments, setDepartments] = useState<any>({}); const [departments, setDepartments] = useState<any>({});
const [did, setDid] = useState(Number(result.get("did")));
useEffect(() => {
setDid(Number(result.get("did")));
if (Number(result.get("did"))) {
let arr = [];
arr.push(Number(result.get("did")));
setDepIds(arr);
}
}, [result.get("did")]);
const columns: ColumnsType<DataType> = [ const columns: ColumnsType<DataType> = [
{ {
@ -247,11 +260,13 @@ const MemberPage = () => {
<div className="tree-main-body"> <div className="tree-main-body">
<div className="left-box"> <div className="left-box">
<TreeDepartment <TreeDepartment
selected={dep_ids}
refresh={refresh} refresh={refresh}
showNum={true} showNum={true}
type="" type=""
text={"部门"} text={"部门"}
onUpdate={(keys: any, title: any) => { onUpdate={(keys: any, title: any) => {
setPage(1);
setDepIds(keys); setDepIds(keys);
var index = title.indexOf("("); var index = title.indexOf("(");
if (index !== -1) { if (index !== -1) {

View File

@ -11,6 +11,7 @@ import {
Pagination, Pagination,
} from "antd"; } from "antd";
import { resource } from "../../../api"; import { resource } from "../../../api";
import { useLocation } from "react-router-dom";
import styles from "./index.module.less"; import styles from "./index.module.less";
import { UploadImageSub } from "../../../compenents/upload-image-button/upload-image-sub"; import { UploadImageSub } from "../../../compenents/upload-image-button/upload-image-sub";
import { TreeCategory, PerButton } from "../../../compenents"; import { TreeCategory, PerButton } from "../../../compenents";
@ -32,6 +33,7 @@ interface ImageItem {
} }
const ResourceImagesPage = () => { const ResourceImagesPage = () => {
const result = new URLSearchParams(useLocation().search);
const [imageList, setImageList] = useState<ImageItem[]>([]); const [imageList, setImageList] = useState<ImageItem[]>([]);
const [refresh, setRefresh] = useState(false); const [refresh, setRefresh] = useState(false);
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
@ -41,8 +43,25 @@ const ResourceImagesPage = () => {
const [selectKey, setSelectKey] = useState<any>([]); const [selectKey, setSelectKey] = useState<any>([]);
const [visibleArr, setVisibleArr] = useState<any>([]); const [visibleArr, setVisibleArr] = useState<any>([]);
const [hoverArr, setHoverArr] = useState<any>([]); const [hoverArr, setHoverArr] = useState<any>([]);
const [selLabel, setLabel] = useState<string>("全部图片"); const [selLabel, setLabel] = useState<string>(
result.get("label") ? String(result.get("label")) : "全部图片"
);
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const [cateId, setCateId] = useState(Number(result.get("cid")));
useEffect(() => {
setCateId(Number(result.get("cid")));
if (Number(result.get("cid"))) {
let arr = [];
arr.push(Number(result.get("cid")));
setCategoryIds(arr);
}
}, [result.get("cid")]);
// 加载图片列表
useEffect(() => {
getImageList();
}, [category_ids, refresh, page, size]);
// 删除图片 // 删除图片
const removeResource = () => { const removeResource = () => {
@ -70,9 +89,6 @@ const ResourceImagesPage = () => {
// 获取图片列表 // 获取图片列表
const getImageList = () => { const getImageList = () => {
if (loading) {
return;
}
setLoading(true); setLoading(true);
let categoryIds = category_ids.join(","); let categoryIds = category_ids.join(",");
resource resource
@ -102,11 +118,6 @@ const ResourceImagesPage = () => {
setRefresh(!refresh); setRefresh(!refresh);
}; };
// 加载图片列表
useEffect(() => {
getImageList();
}, [category_ids, refresh, page, size]);
const onChange = (e: any, id: number) => { const onChange = (e: any, id: number) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -151,9 +162,11 @@ const ResourceImagesPage = () => {
<div className="tree-main-body"> <div className="tree-main-body">
<div className="left-box"> <div className="left-box">
<TreeCategory <TreeCategory
selected={category_ids}
type="no-cate" type="no-cate"
text={"图片"} text={"图片"}
onUpdate={(keys: any, title: any) => { onUpdate={(keys: any, title: any) => {
setPage(1);
setCategoryIds(keys); setCategoryIds(keys);
if (typeof title === "string") { if (typeof title === "string") {
setLabel(title); setLabel(title);
@ -187,15 +200,13 @@ const ResourceImagesPage = () => {
<Button className="mr-16" onClick={() => selectAll()}> <Button className="mr-16" onClick={() => selectAll()}>
</Button> </Button>
<PerButton <Button
disabled={selectKey.length === 0} disabled={selectKey.length === 0}
type="primary" type="primary"
text="删除"
class=""
icon={null}
p="resource-destroy"
onClick={() => removeResource()} onClick={() => removeResource()}
/> >
</Button>
</> </>
)} )}
</div> </div>

View File

@ -84,13 +84,13 @@ const ResourceCategoryPage = () => {
}} }}
/> />
)} )}
{through("resource-destroy") && (
<i <i
className="iconfont icon-icon-delete" className="iconfont icon-icon-delete"
style={{ fontSize: 24 }} style={{ fontSize: 24 }}
onClick={() => removeItem(categories[id][i].id)} onClick={() =>
removeItem(categories[id][i].id, categories[id][i].name)
}
/> />
)}
</div> </div>
</> </>
), ),
@ -119,13 +119,13 @@ const ResourceCategoryPage = () => {
}} }}
/> />
)} )}
{through("resource-destroy") && (
<i <i
className="iconfont icon-icon-delete" className="iconfont icon-icon-delete"
style={{ fontSize: 24 }} style={{ fontSize: 24 }}
onClick={() => removeItem(categories[id][i].id)} onClick={() =>
removeItem(categories[id][i].id, categories[id][i].name)
}
/> />
)}
</div> </div>
</> </>
), ),
@ -142,20 +142,24 @@ const ResourceCategoryPage = () => {
setRefresh(!refresh); setRefresh(!refresh);
}; };
const removeItem = (id: number) => { const removeItem = (id: number, label: string) => {
if (id === 0) { if (id === 0) {
return; return;
} }
resourceCategory.checkDestroy(id).then((res: any) => { resourceCategory.checkDestroy(id).then((res: any) => {
if ( if (
res.data.children &&
res.data.children.length === 0 && res.data.children.length === 0 &&
res.data.courses &&
res.data.courses.length === 0 && res.data.courses.length === 0 &&
res.data.images &&
res.data.images.length === 0 && res.data.images.length === 0 &&
res.data.videos &&
res.data.videos.length === 0 res.data.videos.length === 0
) { ) {
delUser(id); delUser(id);
} else { } else {
if (res.data.children.length > 0) { if (res.data.children && res.data.children.length > 0) {
modal.warning({ modal.warning({
title: "操作确认", title: "操作确认",
centered: true, centered: true,
@ -178,32 +182,38 @@ const ResourceCategoryPage = () => {
content: ( content: (
<p> <p>
{res.data.courses.length > 0 && ( {res.data.courses && res.data.courses.length > 0 && (
<Button <Button
style={{ paddingLeft: 4, paddingRight: 4 }} style={{ paddingLeft: 4, paddingRight: 4 }}
type="link" type="link"
danger danger
onClick={() => navigate("/course")} onClick={() =>
navigate("/course?cid=" + id + "&label=" + label)
}
> >
{res.data.courses.length}线 {res.data.courses.length}线
</Button> </Button>
)} )}
{res.data.videos.length > 0 && ( {res.data.videos && res.data.videos.length > 0 && (
<Button <Button
type="link" type="link"
style={{ paddingLeft: 4, paddingRight: 4 }} style={{ paddingLeft: 4, paddingRight: 4 }}
danger danger
onClick={() => navigate("/videos")} onClick={() =>
navigate("/videos?cid=" + id + "&label=" + label)
}
> >
{res.data.videos.length} {res.data.videos.length}
</Button> </Button>
)} )}
{res.data.images.length > 0 && ( {res.data.images && res.data.images.length > 0 && (
<Button <Button
type="link" type="link"
style={{ paddingLeft: 4, paddingRight: 4 }} style={{ paddingLeft: 4, paddingRight: 4 }}
danger danger
onClick={() => navigate("/images")} onClick={() =>
navigate("/images?cid=" + id + "&label=" + label)
}
> >
{res.data.images.length} {res.data.images.length}
</Button> </Button>

View File

@ -0,0 +1,143 @@
import React, { useState, useEffect } from "react";
import { Modal, Form, Input, message, TreeSelect } from "antd";
import { resource, resourceCategory } from "../../../../../api/index";
interface PropInterface {
id: number;
open: boolean;
onCancel: () => void;
onSuccess: () => void;
}
export const VideosUpdateDialog: React.FC<PropInterface> = ({
id,
open,
onCancel,
onSuccess,
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState<boolean>(true);
const [categories, setCategories] = useState<any>([]);
useEffect(() => {
if (id === 0) {
return;
}
if (open) {
getCategory();
getDetail();
}
}, [id, open]);
const getCategory = () => {
resourceCategory.resourceCategoryList().then((res: any) => {
const categories = res.data.categories;
if (JSON.stringify(categories) !== "{}") {
const new_arr: any = checkArr(categories, 0, null);
setCategories(new_arr);
}
});
};
const getDetail = () => {
resource.videoDetail(id).then((res: any) => {
let data = res.data.resources;
form.setFieldsValue({
name: data.name,
category_id: res.data.category_ids,
});
});
};
const checkArr = (departments: any[], id: number, counts: any) => {
const arr = [];
for (let i = 0; i < departments[id].length; i++) {
if (!departments[departments[id][i].id]) {
arr.push({
title: departments[id][i].name,
value: departments[id][i].id,
});
} else {
const new_arr: any = checkArr(
departments,
departments[id][i].id,
counts
);
arr.push({
title: departments[id][i].name,
value: departments[id][i].id,
children: new_arr,
});
}
}
return arr;
};
const onFinish = (values: any) => {
if (Array.isArray(values.category_id)) {
values.category_id = values.category_id[0];
}
resource.videoUpdate(id, values).then((res: any) => {
message.success("保存成功!");
onSuccess();
});
};
const onFinishFailed = (errorInfo: any) => {
console.log("Failed:", errorInfo);
};
return (
<>
<Modal
title="编辑视频"
centered
forceRender
open={open}
width={416}
onOk={() => form.submit()}
onCancel={() => onCancel()}
maskClosable={false}
>
<div className="float-left mt-24">
<Form
form={form}
name="videos-update"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
label="视频分类"
name="category_id"
rules={[{ required: true, message: "请选择视频分类!" }]}
>
<TreeSelect
showCheckedStrategy={TreeSelect.SHOW_ALL}
allowClear
style={{ width: 200 }}
treeData={categories}
placeholder="视频分类"
treeDefaultExpandAll
/>
</Form.Item>
<Form.Item
label="视频名称"
name="name"
rules={[{ required: true, message: "请输入视频名称!" }]}
>
<Input
allowClear
style={{ width: 200 }}
placeholder="请输入视频名称"
/>
</Form.Item>
</Form>
</div>
</Modal>
</>
);
};

View File

@ -0,0 +1,40 @@
.play-mask {
width: 100%;
height: 100%;
top: 0;
bottom: 0;
left: 0;
right: 0;
position: fixed;
display: flex;
align-items: center;
justify-content: center;
z-index: 200;
.play-dialog {
width: 800px;
height: 450px;
border-radius: 8px;
overflow: hidden;
position: relative;
.close-button {
width: 30px;
height: 30px;
position: absolute;
top: 24px;
right: 24px;
cursor: pointer;
z-index: 1000;
&:hover {
opacity: 0.8;
}
img {
width: 30px;
height: 30px;
}
}
.play-box {
width: 800px;
height: 450px;
}
}
}

View File

@ -0,0 +1,64 @@
import React, { useState, useEffect } from "react";
import styles from "./index.module.less";
import closeIcon from "../../../../../assets/images/commen/close.png";
interface PropInterface {
id: number;
url: string;
open: boolean;
onCancel: () => void;
}
declare const window: any;
export const VideoPlayDialog: React.FC<PropInterface> = ({
id,
url,
open,
onCancel,
}) => {
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
if (open && url) {
initDPlayer(url);
}
}, [id, open, url]);
const initDPlayer = (playUrl: string) => {
window.player = new window.DPlayer({
container: document.getElementById("meedu-player-container"),
autoplay: false,
video: {
url: playUrl,
},
});
window.player.on("ended", () => {
window.player && window.player.destroy();
});
};
return (
<>
{open && (
<div className={styles["play-mask"]}>
<div className={styles["play-dialog"]}>
<div
className={styles["close-button"]}
onClick={() => {
window.player && window.player.destroy();
onCancel();
}}
>
<img src={closeIcon} />
</div>
<div
className={styles["play-box"]}
id="meedu-player-container"
></div>
</div>
</div>
)}
</>
);
};

View File

@ -1,12 +1,16 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Modal, Table, message, Space } from "antd"; import { Modal, Table, message, Space, Dropdown, Button } from "antd";
import type { MenuProps } from "antd";
import { resource } from "../../../api"; import { resource } from "../../../api";
// import styles from "./index.module.less"; // import styles from "./index.module.less";
import { ExclamationCircleFilled } from "@ant-design/icons"; import { useLocation } from "react-router-dom";
import { DownOutlined, ExclamationCircleFilled } from "@ant-design/icons";
import type { ColumnsType } from "antd/es/table"; import type { ColumnsType } from "antd/es/table";
import { dateFormat } from "../../../utils/index"; import { dateFormat } from "../../../utils/index";
import { TreeCategory, DurationText, PerButton } from "../../../compenents"; import { TreeCategory, DurationText, PerButton } from "../../../compenents";
import { UploadVideoButton } from "../../../compenents/upload-video-button"; import { UploadVideoButton } from "../../../compenents/upload-video-button";
import { VideoPlayDialog } from "./compenents/video-play-dialog";
import { VideosUpdateDialog } from "./compenents/update-dialog";
const { confirm } = Modal; const { confirm } = Modal;
@ -18,6 +22,7 @@ interface DataType {
} }
const ResourceVideosPage = () => { const ResourceVideosPage = () => {
const result = new URLSearchParams(useLocation().search);
const [videoList, setVideoList] = useState<any>([]); const [videoList, setVideoList] = useState<any>([]);
const [videosExtra, setVideoExtra] = useState<any>([]); const [videosExtra, setVideoExtra] = useState<any>([]);
const [adminUsers, setAdminUsers] = useState<any>({}); const [adminUsers, setAdminUsers] = useState<any>({});
@ -27,21 +32,27 @@ const ResourceVideosPage = () => {
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [category_ids, setCategoryIds] = useState<any>([]); const [category_ids, setCategoryIds] = useState<any>([]);
const [selLabel, setLabel] = useState<string>("全部视频"); const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
const [selLabel, setLabel] = useState<string>(
result.get("label") ? String(result.get("label")) : "全部视频"
);
const [cateId, setCateId] = useState(Number(result.get("cid")));
const [updateVisible, setUpdateVisible] = useState<boolean>(false);
const [playVisible, setPlayeVisible] = useState<boolean>(false);
const [multiConfig, setMultiConfig] = useState<boolean>(false);
const [updateId, setUpdateId] = useState(0);
const [playUrl, setPlayUrl] = useState<string>("");
useEffect(() => {
setCateId(Number(result.get("cid")));
if (Number(result.get("cid"))) {
let arr = [];
arr.push(Number(result.get("cid")));
setCategoryIds(arr);
}
}, [result.get("cid")]);
const columns: ColumnsType<DataType> = [ const columns: ColumnsType<DataType> = [
// {
// title: "封面",
// dataIndex: "id",
// render: (id: string) => (
// <Image
// preview={false}
// width={120}
// height={80}
// src={videosExtra[id].poster}
// ></Image>
// ),
// },
{ {
title: "视频名称", title: "视频名称",
dataIndex: "name", dataIndex: "name",
@ -80,21 +91,69 @@ const ResourceVideosPage = () => {
title: "操作", title: "操作",
key: "action", key: "action",
fixed: "right", fixed: "right",
width: 100, width: 160,
render: (_, record: any) => ( render: (_, record: any) => {
<Space size="small"> const items: MenuProps["items"] = [
<PerButton {
key: "1",
label: (
<Button
type="link" type="link"
text="删除" className="b-link c-red"
class="b-link c-red" onClick={() => {
icon={null} setUpdateId(record.id);
p="resource-destroy" setUpdateVisible(true);
onClick={() => removeResource(record.id)} }}
disabled={null} >
/>
</Space> </Button>
), ),
}, },
{
key: "2",
label: (
<Button
type="link"
className="b-link c-red"
onClick={() => removeResource(record.id)}
>
</Button>
),
},
];
return (
<Space size="small">
<Button
type="link"
size="small"
className="b-n-link c-red"
onClick={() => {
setUpdateId(record.id);
setPlayUrl(record.url);
setPlayeVisible(true);
}}
>
</Button>
<div className="form-column"></div>
<Dropdown menu={{ items }}>
<Button
type="link"
className="b-link c-red"
onClick={(e) => e.preventDefault()}
>
<Space size="small" align="center">
<DownOutlined />
</Space>
</Button>
</Dropdown>
</Space>
);
},
},
]; ];
// 删除图片 // 删除图片
@ -105,7 +164,7 @@ const ResourceVideosPage = () => {
confirm({ confirm({
title: "操作确认", title: "操作确认",
icon: <ExclamationCircleFilled />, icon: <ExclamationCircleFilled />,
content: "确认删除此视频", content: "删除前请检查选中视频文件无关联课程,确认删除?",
centered: true, centered: true,
okText: "确认", okText: "确认",
cancelText: "取消", cancelText: "取消",
@ -121,6 +180,29 @@ const ResourceVideosPage = () => {
}); });
}; };
const removeResourceMulti = () => {
if (selectedRowKeys.length === 0) {
return;
}
confirm({
title: "操作确认",
icon: <ExclamationCircleFilled />,
content: "删除前请检查选中视频文件无关联课程,确认删除?",
centered: true,
okText: "确认",
cancelText: "取消",
onOk() {
resource.destroyResourceMulti(selectedRowKeys).then(() => {
message.success("删除成功");
resetVideoList();
});
},
onCancel() {
console.log("Cancel");
},
});
};
// 获取视频列表 // 获取视频列表
const getVideoList = () => { const getVideoList = () => {
setLoading(true); setLoading(true);
@ -138,11 +220,13 @@ const ResourceVideosPage = () => {
console.log("错误,", err); console.log("错误,", err);
}); });
}; };
// 重置列表 // 重置列表
const resetVideoList = () => { const resetVideoList = () => {
setPage(1); setPage(1);
setSize(10); setSize(10);
setVideoList([]); setVideoList([]);
setSelectedRowKeys([]);
setRefresh(!refresh); setRefresh(!refresh);
}; };
@ -165,14 +249,22 @@ const ResourceVideosPage = () => {
setSize(pageSize); setSize(pageSize);
}; };
const rowSelection = {
onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
setSelectedRowKeys(selectedRowKeys);
},
};
return ( return (
<> <>
<div className="tree-main-body"> <div className="tree-main-body">
<div className="left-box"> <div className="left-box">
<TreeCategory <TreeCategory
selected={category_ids}
type="no-cate" type="no-cate"
text={"视频"} text={"视频"}
onUpdate={(keys: any, title: any) => { onUpdate={(keys: any, title: any) => {
setPage(1);
setCategoryIds(keys); setCategoryIds(keys);
if (typeof title === "string") { if (typeof title === "string") {
setLabel(title); setLabel(title);
@ -186,7 +278,8 @@ const ResourceVideosPage = () => {
<div className="d-flex playedu-main-title float-left mb-24"> <div className="d-flex playedu-main-title float-left mb-24">
| {selLabel} | {selLabel}
</div> </div>
<div className="float-left mb-24"> <div className="float-left j-b-flex mb-24">
<div>
<UploadVideoButton <UploadVideoButton
categoryIds={category_ids} categoryIds={category_ids}
onUpdate={() => { onUpdate={() => {
@ -194,7 +287,40 @@ const ResourceVideosPage = () => {
}} }}
></UploadVideoButton> ></UploadVideoButton>
</div> </div>
<div className="d-flex">
<Button
type="default"
className="mr-16"
onClick={() => {
setSelectedRowKeys([]);
setMultiConfig(!multiConfig);
}}
>
{multiConfig ? "取消操作" : "批量操作"}
</Button>
<Button
type="default"
onClick={() => removeResourceMulti()}
disabled={selectedRowKeys.length === 0}
>
</Button>
</div>
</div>
<div className="float-left"> <div className="float-left">
{multiConfig ? (
<Table
rowSelection={{
type: "checkbox",
...rowSelection,
}}
columns={columns}
dataSource={videoList}
loading={loading}
pagination={paginationProps}
rowKey={(record) => record.id}
/>
) : (
<Table <Table
columns={columns} columns={columns}
dataSource={videoList} dataSource={videoList}
@ -202,8 +328,24 @@ const ResourceVideosPage = () => {
pagination={paginationProps} pagination={paginationProps}
rowKey={(record) => record.id} rowKey={(record) => record.id}
/> />
)}
</div> </div>
</div> </div>
<VideoPlayDialog
id={Number(updateId)}
open={playVisible}
url={playUrl}
onCancel={() => setPlayeVisible(false)}
></VideoPlayDialog>
<VideosUpdateDialog
id={Number(updateId)}
open={updateVisible}
onCancel={() => setUpdateVisible(false)}
onSuccess={() => {
setUpdateVisible(false);
setRefresh(!refresh);
}}
></VideosUpdateDialog>
</div> </div>
</> </>
); );

View File

@ -40,6 +40,7 @@ const SystemAdministratorPage = () => {
const [role_ids, setRoleIds] = useState<any>([]); const [role_ids, setRoleIds] = useState<any>([]);
const [selLabel, setLabel] = useState<string>("全部管理员"); const [selLabel, setLabel] = useState<string>("全部管理员");
const [roleDelSuccess, setRoleDelSuccess] = useState(false); const [roleDelSuccess, setRoleDelSuccess] = useState(false);
const [isSuper, setIsSuper] = useState(false);
const [name, setName] = useState<string>(""); const [name, setName] = useState<string>("");
@ -216,9 +217,10 @@ const SystemAdministratorPage = () => {
refresh={refresh} refresh={refresh}
type="" type=""
text={"管理员"} text={"管理员"}
onUpdate={(keys: any, title: any) => { onUpdate={(keys: any, title: any, isSuper: boolean) => {
setRoleIds(keys); setRoleIds(keys);
setLabel(title); setLabel(title);
setIsSuper(isSuper);
}} }}
/> />
</div> </div>
@ -248,7 +250,7 @@ const SystemAdministratorPage = () => {
disabled={null} disabled={null}
/> />
)} )}
{role_ids.length > 0 && ( {!isSuper && role_ids.length > 0 && (
<> <>
<PerButton <PerButton
text="角色权限" text="角色权限"

View File

@ -72,11 +72,6 @@ export const SystemAdminrolesCreate: React.FC<PropInterface> = ({
value: "线上课-n", value: "线上课-n",
children: [], children: [],
}, },
{
title: "资源",
value: "资源-n",
children: [],
},
{ {
title: "资源分类", title: "资源分类",
value: "资源分类-n", value: "资源分类-n",
@ -87,6 +82,11 @@ export const SystemAdminrolesCreate: React.FC<PropInterface> = ({
value: "部门-n", value: "部门-n",
children: [], children: [],
}, },
{
title: "系统配置",
value: "系统配置-n",
children: [],
},
{ {
title: "其它", title: "其它",
value: "其它-n", value: "其它-n",

View File

@ -75,11 +75,6 @@ export const SystemAdminrolesUpdate: React.FC<PropInterface> = ({
value: "线上课-n", value: "线上课-n",
children: [], children: [],
}, },
{
title: "资源",
value: "资源-n",
children: [],
},
{ {
title: "资源分类", title: "资源分类",
value: "资源分类-n", value: "资源分类-n",
@ -90,6 +85,11 @@ export const SystemAdminrolesUpdate: React.FC<PropInterface> = ({
value: "部门-n", value: "部门-n",
children: [], children: [],
}, },
{
title: "系统配置",
value: "系统配置-n",
children: [],
},
{ {
title: "其它", title: "其它",
value: "其它-n", value: "其它-n",

View File

@ -52,6 +52,10 @@ const SystemConfigPage = () => {
form.setFieldsValue({ form.setFieldsValue({
"system.api_url": configData[i].key_value, "system.api_url": configData[i].key_value,
}); });
} else if (configData[i].key_name === "system.api_url") {
form.setFieldsValue({
"system.api_url": configData[i].key_value,
});
} else if (configData[i].key_name === "system.pc_url") { } else if (configData[i].key_name === "system.pc_url") {
form.setFieldsValue({ form.setFieldsValue({
"system.pc_url": configData[i].key_value, "system.pc_url": configData[i].key_value,
@ -275,6 +279,13 @@ const SystemConfigPage = () => {
</div> </div>
</Form.Item> </Form.Item>
)} )}
<Form.Item
style={{ marginBottom: 30 }}
label="API访问地址"
name="system.api_url"
>
<Input style={{ width: 274 }} placeholder="请填写API访问地址" />
</Form.Item>
<Form.Item <Form.Item
style={{ marginBottom: 30 }} style={{ marginBottom: 30 }}
label="网站标题" label="网站标题"
@ -297,13 +308,7 @@ const SystemConfigPage = () => {
placeholder="请填写网站页脚" placeholder="请填写网站页脚"
/> />
</Form.Item> </Form.Item>
{/* <Form.Item {/*
style={{ marginBottom: 30 }}
label="API访问地址"
name="system.api_url"
>
<Input style={{ width: 274 }} placeholder="请填写API访问地址" />
</Form.Item>
<Form.Item <Form.Item
style={{ marginBottom: 30 }} style={{ marginBottom: 30 }}
label="PC端访问地址" label="PC端访问地址"
@ -373,6 +378,14 @@ const SystemConfigPage = () => {
style={{ width: 274 }} style={{ width: 274 }}
allowClear allowClear
placeholder="自定义跑马灯内容" placeholder="自定义跑马灯内容"
onChange={(e) => {
const { value } = e.target;
if (!value && e.type !== "change") {
setNameChecked(false);
setEmailChecked(false);
setIdCardChecked(false);
}
}}
/> />
</Form.Item> </Form.Item>
<Checkbox <Checkbox

View File

@ -124,3 +124,12 @@ export function ValidataCredentials(value: any) {
} }
} }
} }
export function checkUrl(value: any) {
let url = value;
let str = url.substr(url.length - 1, 1);
if (str !== "/") {
url = url + "/";
}
return url;
}