mirror of
https://github.com/PlayEdu/backend
synced 2025-07-18 00:57:38 +08:00
commit
7dc58e2fde
@ -8,9 +8,15 @@
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
|
||||
/>
|
||||
<title>管理后台</title>
|
||||
<script src="/js/DPlayer.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<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>
|
||||
</html>
|
||||
|
1
public/js/DPlayer.min.js
vendored
Normal file
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
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
21
public/js/xg/index.js
Normal file
File diff suppressed because one or more lines are too long
@ -61,3 +61,11 @@ export function destroyResourceMulti(ids: number[]) {
|
||||
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);
|
||||
}
|
||||
|
BIN
src/assets/images/commen/close.png
Normal file
BIN
src/assets/images/commen/close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 736 B |
@ -1,16 +1,25 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Menu } from "antd";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import styles from "./index.module.less";
|
||||
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 {
|
||||
key,
|
||||
icon,
|
||||
children,
|
||||
label,
|
||||
type,
|
||||
permission,
|
||||
};
|
||||
}
|
||||
const items = [
|
||||
@ -19,6 +28,7 @@ const items = [
|
||||
"/",
|
||||
<i className={`iconfont icon-icon-home`} />,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
),
|
||||
getItem(
|
||||
@ -26,6 +36,7 @@ const items = [
|
||||
"/resource-category",
|
||||
<i className="iconfont icon-icon-category" />,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
),
|
||||
getItem(
|
||||
@ -33,16 +44,18 @@ const items = [
|
||||
"resource",
|
||||
<i className="iconfont icon-icon-file" />,
|
||||
[
|
||||
getItem("视频", "/videos", null, null, null),
|
||||
getItem("图片", "/images", null, null, null),
|
||||
getItem("视频", "/videos", null, null, null, null),
|
||||
getItem("图片", "/images", null, null, null, null),
|
||||
],
|
||||
null,
|
||||
null
|
||||
),
|
||||
getItem(
|
||||
"课程中心",
|
||||
"courses",
|
||||
<i className="iconfont icon-icon-study" />,
|
||||
[getItem("线上课", "/course", null, null, null)],
|
||||
[getItem("线上课", "/course", null, null, null, "course")],
|
||||
null,
|
||||
null
|
||||
),
|
||||
getItem(
|
||||
@ -50,9 +63,10 @@ const items = [
|
||||
"user",
|
||||
<i className="iconfont icon-icon-user" />,
|
||||
[
|
||||
getItem("学员", "/member/index", null, null, null),
|
||||
getItem("部门", "/department", null, null, null),
|
||||
getItem("学员", "/member/index", null, null, null, "user-index"),
|
||||
getItem("部门", "/department", null, null, null, "department-cud"),
|
||||
],
|
||||
null,
|
||||
null
|
||||
),
|
||||
getItem(
|
||||
@ -60,26 +74,40 @@ const items = [
|
||||
"system",
|
||||
<i className="iconfont icon-icon-setting" />,
|
||||
[
|
||||
getItem("系统配置", "/system/config/index", null, null, null),
|
||||
getItem("管理人员", "/system/administrator", null, null, null),
|
||||
// getItem("角色配置", "/system/adminroles", null, null, null),
|
||||
getItem(
|
||||
"系统配置",
|
||||
"/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
|
||||
),
|
||||
];
|
||||
|
||||
const children2Parent: any = {
|
||||
"^/video": ["resource"],
|
||||
"^/image": ["resource"],
|
||||
"^/member": ["user"],
|
||||
"^/department": ["user"],
|
||||
"^/course": ["courses"],
|
||||
"^/system": ["system"],
|
||||
};
|
||||
|
||||
export const LeftMenu: React.FC = () => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const children2Parent: any = {
|
||||
"^/video": ["resource"],
|
||||
"^/image": ["resource"],
|
||||
"^/member": ["user"],
|
||||
"^/department": ["user"],
|
||||
"^/course": ["courses"],
|
||||
"^/system": ["system"],
|
||||
};
|
||||
|
||||
const hit = (pathname: string): string[] => {
|
||||
for (let p in children2Parent) {
|
||||
@ -104,7 +132,6 @@ export const LeftMenu: React.FC = () => {
|
||||
}
|
||||
newOpenKeys.push(openKeys[i]);
|
||||
}
|
||||
|
||||
return newOpenKeys;
|
||||
};
|
||||
|
||||
@ -114,11 +141,54 @@ export const LeftMenu: React.FC = () => {
|
||||
]);
|
||||
// 展开菜单
|
||||
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) => {
|
||||
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(() => {
|
||||
if (location.pathname.indexOf("/course/user") !== -1) {
|
||||
setSelectedKeys(["/course"]);
|
||||
@ -159,7 +229,7 @@ export const LeftMenu: React.FC = () => {
|
||||
selectedKeys={selectedKeys}
|
||||
openKeys={openKeys}
|
||||
mode="inline"
|
||||
items={items}
|
||||
items={activeMenus}
|
||||
onSelect={(data: any) => {
|
||||
setSelectedKeys(data.selectedKeys);
|
||||
}}
|
||||
|
@ -13,13 +13,14 @@ interface PropInterface {
|
||||
roleDelSuccess: boolean;
|
||||
type: string;
|
||||
text: string;
|
||||
onUpdate: (keys: any, title: any) => void;
|
||||
onUpdate: (keys: any, title: any, isSuper: boolean) => void;
|
||||
}
|
||||
|
||||
export const TreeAdminroles = (props: PropInterface) => {
|
||||
const [treeData, setTreeData] = useState<any>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [selectKey, setSelectKey] = useState<any>([]);
|
||||
const [superId, setSuperId] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
onSelect([], "");
|
||||
@ -28,6 +29,7 @@ export const TreeAdminroles = (props: PropInterface) => {
|
||||
useEffect(() => {
|
||||
adminRole.adminRoleList().then((res: any) => {
|
||||
let adminrole = res.data;
|
||||
let superId = 0;
|
||||
if (adminrole.length > 0) {
|
||||
const new_arr: Option[] = [];
|
||||
for (let i = 0; i < adminrole.length; i++) {
|
||||
@ -36,9 +38,13 @@ export const TreeAdminroles = (props: PropInterface) => {
|
||||
key: adminrole[i].id,
|
||||
children: [],
|
||||
});
|
||||
if (adminrole[i].slug === "super-role") {
|
||||
superId = adminrole[i].id;
|
||||
}
|
||||
}
|
||||
setTreeData(new_arr);
|
||||
}
|
||||
setSuperId(superId);
|
||||
});
|
||||
}, [props.refresh]);
|
||||
|
||||
@ -47,7 +53,11 @@ export const TreeAdminroles = (props: PropInterface) => {
|
||||
if (info) {
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -5,13 +5,13 @@ import { resourceCategory } from "../../api/index";
|
||||
interface Option {
|
||||
key: string | number;
|
||||
title: any;
|
||||
|
||||
children?: Option[];
|
||||
}
|
||||
|
||||
interface PropInterface {
|
||||
type: string;
|
||||
text: string;
|
||||
selected: any;
|
||||
onUpdate: (keys: any, title: any) => void;
|
||||
}
|
||||
|
||||
@ -20,6 +20,12 @@ export const TreeCategory = (props: PropInterface) => {
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [selectKey, setSelectKey] = useState<any>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.selected && props.selected.length > 0) {
|
||||
setSelectKey(props.selected);
|
||||
}
|
||||
}, [props.selected]);
|
||||
|
||||
useEffect(() => {
|
||||
resourceCategory.resourceCategoryList().then((res: any) => {
|
||||
const categories = res.data.categories;
|
||||
|
@ -13,6 +13,7 @@ interface PropInterface {
|
||||
text: string;
|
||||
refresh: boolean;
|
||||
showNum: boolean;
|
||||
selected: any;
|
||||
onUpdate: (keys: any, title: any) => void;
|
||||
}
|
||||
|
||||
@ -22,6 +23,12 @@ export const TreeDepartment = (props: PropInterface) => {
|
||||
const [selectKey, setSelectKey] = useState<any>([]);
|
||||
const [userTotal, setUserTotal] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.selected && props.selected.length > 0) {
|
||||
setSelectKey(props.selected);
|
||||
}
|
||||
}, [props.selected]);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
department.departmentList().then((res: any) => {
|
||||
|
@ -110,6 +110,7 @@ export const UploadImageButton = (props: PropsInterface) => {
|
||||
<Row style={{ width: 752, minHeight: 520, marginTop: 24 }}>
|
||||
<Col span={7}>
|
||||
<TreeCategory
|
||||
selected={category_ids}
|
||||
type="no-cate"
|
||||
text={"图片"}
|
||||
onUpdate={(keys: any) => {
|
||||
|
@ -2,7 +2,7 @@ import { Button, message, Modal } from "antd";
|
||||
import Dragger from "antd/es/upload/Dragger";
|
||||
import { useState } from "react";
|
||||
import config from "../../../js/config";
|
||||
import { getToken } from "../../../utils";
|
||||
import { getToken, checkUrl } from "../../../utils";
|
||||
import { InboxOutlined } from "@ant-design/icons";
|
||||
|
||||
interface PropsInterface {
|
||||
@ -17,8 +17,8 @@ export const UploadImageSub = (props: PropsInterface) => {
|
||||
name: "file",
|
||||
multiple: true,
|
||||
action:
|
||||
config.app_url +
|
||||
"/backend/v1/upload/minio?category_ids=" +
|
||||
checkUrl(config.app_url) +
|
||||
"backend/v1/upload/minio?category_ids=" +
|
||||
props.categoryIds.join(","),
|
||||
headers: {
|
||||
authorization: "Bearer " + getToken(),
|
||||
|
@ -173,6 +173,7 @@ export const UploadVideoSub = (props: PropsInterface) => {
|
||||
<Row style={{ width: 752, minHeight: 520 }}>
|
||||
<Col span={7}>
|
||||
<TreeCategory
|
||||
selected={[]}
|
||||
type="no-cate"
|
||||
text={props.label}
|
||||
onUpdate={(keys: any) => setCategoryIds(keys)}
|
||||
|
@ -519,16 +519,27 @@ textarea.ant-input {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ant-modal-confirm-btns > .ant-btn-default:hover {
|
||||
color: #ff4d4f !important;
|
||||
border-color: #ff4d4f;
|
||||
.ant-modal-confirm-btns > .ant-btn-default {
|
||||
outline: none;
|
||||
box-shadow: none !important;
|
||||
&:hover {
|
||||
box-shadow: none !important;
|
||||
color: #ff4d4f !important;
|
||||
border-color: #ff4d4f;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-modal-confirm-btns > .ant-btn-primary {
|
||||
border: none;
|
||||
box-shadow: none !important;
|
||||
background-color: #ff4d4f !important;
|
||||
color: #fff;
|
||||
outline: none;
|
||||
&:hover {
|
||||
box-shadow: none !important;
|
||||
opacity: 0.8;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
.ant-tree-treenode {
|
||||
|
@ -482,9 +482,9 @@ export const CourseCreate: React.FC<PropInterface> = ({
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="必修选修"
|
||||
label="课程属性"
|
||||
name="isRequired"
|
||||
rules={[{ required: true, message: "请选择必修选修!" }]}
|
||||
rules={[{ required: true, message: "请选择课程属性!" }]}
|
||||
>
|
||||
<Radio.Group>
|
||||
<Radio value={1}>必修课</Radio>
|
||||
|
@ -230,9 +230,9 @@ export const CourseUpdate: React.FC<PropInterface> = ({
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="必修选修"
|
||||
label="课程属性"
|
||||
name="isRequired"
|
||||
rules={[{ required: true, message: "请选择必修选修!" }]}
|
||||
rules={[{ required: true, message: "请选择课程属性!" }]}
|
||||
>
|
||||
<Radio.Group>
|
||||
<Radio value={1}>必修课</Radio>
|
||||
|
@ -21,7 +21,7 @@ import {
|
||||
import type { MenuProps } from "antd";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
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 type { TabsProps } from "antd";
|
||||
import { CourseCreate } from "./compenents/create";
|
||||
@ -40,6 +40,7 @@ interface DataType {
|
||||
}
|
||||
|
||||
const CoursePage = () => {
|
||||
const result = new URLSearchParams(useLocation().search);
|
||||
const navigate = useNavigate();
|
||||
const [list, setList] = useState<any>([]);
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
@ -50,18 +51,43 @@ const CoursePage = () => {
|
||||
const [category_ids, setCategoryIds] = useState<any>([]);
|
||||
const [title, setTitle] = useState<string>("");
|
||||
const [dep_ids, setDepIds] = useState<any>([]);
|
||||
const [selLabel, setLabel] = useState<string>("全部分类");
|
||||
const [selDepLabel, setDepLabel] = useState<string>("全部部门");
|
||||
const [selLabel, setLabel] = 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_dep_ids, setCourseDepIds] = useState<any>({});
|
||||
const [categories, setCategories] = 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 [updateVisible, setUpdateVisible] = useState<boolean>(false);
|
||||
const [updateHourVisible, setHourUpdateVisible] = useState<boolean>(false);
|
||||
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"] = [
|
||||
{
|
||||
@ -70,9 +96,11 @@ const CoursePage = () => {
|
||||
children: (
|
||||
<div className="float-left">
|
||||
<TreeCategory
|
||||
selected={category_ids}
|
||||
type=""
|
||||
text={"分类"}
|
||||
onUpdate={(keys: any, title: any) => {
|
||||
setPage(1);
|
||||
setCategoryIds(keys);
|
||||
if (typeof title === "string") {
|
||||
setLabel(title);
|
||||
@ -90,11 +118,13 @@ const CoursePage = () => {
|
||||
children: (
|
||||
<div className="float-left">
|
||||
<TreeDepartment
|
||||
selected={dep_ids}
|
||||
refresh={refresh}
|
||||
showNum={false}
|
||||
type="no-course"
|
||||
text={"部门"}
|
||||
onUpdate={(keys: any, title: any) => {
|
||||
setPage(1);
|
||||
setDepIds(keys);
|
||||
setDepLabel(title);
|
||||
}}
|
||||
@ -288,7 +318,7 @@ const CoursePage = () => {
|
||||
setLoading(true);
|
||||
let categoryIds = "";
|
||||
let depIds = "";
|
||||
if (tabKey === 1) {
|
||||
if (tabKey === "1") {
|
||||
categoryIds = category_ids.join(",");
|
||||
} else {
|
||||
depIds = dep_ids.join(",");
|
||||
@ -317,11 +347,6 @@ const CoursePage = () => {
|
||||
setRefresh(!refresh);
|
||||
};
|
||||
|
||||
// 加载列表
|
||||
useEffect(() => {
|
||||
getList();
|
||||
}, [category_ids, dep_ids, refresh, page, size, tabKey]);
|
||||
|
||||
const paginationProps = {
|
||||
current: page, //当前页码
|
||||
pageSize: size,
|
||||
@ -337,7 +362,7 @@ const CoursePage = () => {
|
||||
};
|
||||
|
||||
const onChange = (key: string) => {
|
||||
setTabKey(Number(key));
|
||||
setTabKey(key);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -345,7 +370,7 @@ const CoursePage = () => {
|
||||
<div className="tree-main-body">
|
||||
<div className="left-box">
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
defaultActiveKey={tabKey}
|
||||
centered
|
||||
tabBarGutter={55}
|
||||
items={items}
|
||||
@ -354,7 +379,7 @@ const CoursePage = () => {
|
||||
</div>
|
||||
<div className="right-box">
|
||||
<div className="playedu-main-title float-left mb-24">
|
||||
线上课 | {tabKey === 1 ? selLabel : selDepLabel}
|
||||
线上课 | {tabKey === "1" ? selLabel : selDepLabel}
|
||||
</div>
|
||||
<div className="float-left j-b-flex mb-24">
|
||||
<div className="d-flex">
|
||||
@ -406,8 +431,8 @@ const CoursePage = () => {
|
||||
rowKey={(record) => record.id}
|
||||
/>
|
||||
<CourseCreate
|
||||
cateIds={tabKey === 1 ? category_ids : []}
|
||||
depIds={tabKey === 2 ? dep_ids : []}
|
||||
cateIds={tabKey === "1" ? category_ids : []}
|
||||
depIds={tabKey === "2" ? dep_ids : []}
|
||||
open={createVisible}
|
||||
onCancel={() => {
|
||||
setCreateVisible(false);
|
||||
|
@ -89,7 +89,12 @@ const DepartmentPage = () => {
|
||||
<i
|
||||
className="iconfont icon-icon-delete"
|
||||
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
|
||||
className="iconfont icon-icon-delete"
|
||||
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);
|
||||
};
|
||||
|
||||
const removeItem = (id: number) => {
|
||||
const removeItem = (id: number, label: string) => {
|
||||
if (id === 0) {
|
||||
return;
|
||||
}
|
||||
department.checkDestroy(id).then((res: any) => {
|
||||
if (
|
||||
res.data.children &&
|
||||
res.data.children.length === 0 &&
|
||||
res.data.courses &&
|
||||
res.data.courses.length === 0 &&
|
||||
res.data.users &&
|
||||
res.data.users.length === 0
|
||||
) {
|
||||
delUser(id);
|
||||
} else {
|
||||
if (res.data.children.length > 0) {
|
||||
if (res.data.children && res.data.children.length > 0) {
|
||||
modal.warning({
|
||||
title: "操作确认",
|
||||
centered: true,
|
||||
@ -179,22 +192,26 @@ const DepartmentPage = () => {
|
||||
content: (
|
||||
<p>
|
||||
此部门已关联
|
||||
{res.data.courses.length > 0 && (
|
||||
{res.data.courses && res.data.courses.length > 0 && (
|
||||
<Button
|
||||
style={{ paddingLeft: 4, paddingRight: 4 }}
|
||||
type="link"
|
||||
danger
|
||||
onClick={() => navigate("/course")}
|
||||
onClick={() =>
|
||||
navigate("/course?did=" + id + "&label=" + label)
|
||||
}
|
||||
>
|
||||
({res.data.courses.length}个线上课程),
|
||||
</Button>
|
||||
)}
|
||||
{res.data.users.length > 0 && (
|
||||
{res.data.users && res.data.users.length > 0 && (
|
||||
<Button
|
||||
type="link"
|
||||
style={{ paddingLeft: 4, paddingRight: 4 }}
|
||||
danger
|
||||
onClick={() => navigate("/member/index")}
|
||||
onClick={() =>
|
||||
navigate("/member/index?did=" + id + "&label=" + label)
|
||||
}
|
||||
>
|
||||
({res.data.users.length}个学员),
|
||||
</Button>
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
} from "@ant-design/icons";
|
||||
import { user } from "../../api/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 { MemberCreate } from "./compenents/create";
|
||||
import { MemberUpdate } from "./compenents/update";
|
||||
@ -37,6 +37,7 @@ interface DataType {
|
||||
}
|
||||
|
||||
const MemberPage = () => {
|
||||
const result = new URLSearchParams(useLocation().search);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [page, setPage] = useState(1);
|
||||
const [size, setSize] = useState(10);
|
||||
@ -47,12 +48,24 @@ const MemberPage = () => {
|
||||
const [nickname, setNickname] = useState<string>("");
|
||||
const [email, setEmail] = useState<string>("");
|
||||
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 [updateVisible, setUpdateVisible] = useState<boolean>(false);
|
||||
const [mid, setMid] = useState<number>(0);
|
||||
const [user_dep_ids, setUserDepIds] = 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> = [
|
||||
{
|
||||
@ -247,11 +260,13 @@ const MemberPage = () => {
|
||||
<div className="tree-main-body">
|
||||
<div className="left-box">
|
||||
<TreeDepartment
|
||||
selected={dep_ids}
|
||||
refresh={refresh}
|
||||
showNum={true}
|
||||
type=""
|
||||
text={"部门"}
|
||||
onUpdate={(keys: any, title: any) => {
|
||||
setPage(1);
|
||||
setDepIds(keys);
|
||||
var index = title.indexOf("(");
|
||||
if (index !== -1) {
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
Pagination,
|
||||
} from "antd";
|
||||
import { resource } from "../../../api";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import styles from "./index.module.less";
|
||||
import { UploadImageSub } from "../../../compenents/upload-image-button/upload-image-sub";
|
||||
import { TreeCategory, PerButton } from "../../../compenents";
|
||||
@ -32,6 +33,7 @@ interface ImageItem {
|
||||
}
|
||||
|
||||
const ResourceImagesPage = () => {
|
||||
const result = new URLSearchParams(useLocation().search);
|
||||
const [imageList, setImageList] = useState<ImageItem[]>([]);
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
const [page, setPage] = useState(1);
|
||||
@ -41,8 +43,25 @@ const ResourceImagesPage = () => {
|
||||
const [selectKey, setSelectKey] = useState<any>([]);
|
||||
const [visibleArr, setVisibleArr] = 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 [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 = () => {
|
||||
@ -70,9 +89,6 @@ const ResourceImagesPage = () => {
|
||||
|
||||
// 获取图片列表
|
||||
const getImageList = () => {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
let categoryIds = category_ids.join(",");
|
||||
resource
|
||||
@ -102,11 +118,6 @@ const ResourceImagesPage = () => {
|
||||
setRefresh(!refresh);
|
||||
};
|
||||
|
||||
// 加载图片列表
|
||||
useEffect(() => {
|
||||
getImageList();
|
||||
}, [category_ids, refresh, page, size]);
|
||||
|
||||
const onChange = (e: any, id: number) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@ -151,9 +162,11 @@ const ResourceImagesPage = () => {
|
||||
<div className="tree-main-body">
|
||||
<div className="left-box">
|
||||
<TreeCategory
|
||||
selected={category_ids}
|
||||
type="no-cate"
|
||||
text={"图片"}
|
||||
onUpdate={(keys: any, title: any) => {
|
||||
setPage(1);
|
||||
setCategoryIds(keys);
|
||||
if (typeof title === "string") {
|
||||
setLabel(title);
|
||||
@ -187,15 +200,13 @@ const ResourceImagesPage = () => {
|
||||
<Button className="mr-16" onClick={() => selectAll()}>
|
||||
全选
|
||||
</Button>
|
||||
<PerButton
|
||||
<Button
|
||||
disabled={selectKey.length === 0}
|
||||
type="primary"
|
||||
text="删除"
|
||||
class=""
|
||||
icon={null}
|
||||
p="resource-destroy"
|
||||
onClick={() => removeResource()}
|
||||
/>
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
@ -84,13 +84,13 @@ const ResourceCategoryPage = () => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{through("resource-destroy") && (
|
||||
<i
|
||||
className="iconfont icon-icon-delete"
|
||||
style={{ fontSize: 24 }}
|
||||
onClick={() => removeItem(categories[id][i].id)}
|
||||
/>
|
||||
)}
|
||||
<i
|
||||
className="iconfont icon-icon-delete"
|
||||
style={{ fontSize: 24 }}
|
||||
onClick={() =>
|
||||
removeItem(categories[id][i].id, categories[id][i].name)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
@ -119,13 +119,13 @@ const ResourceCategoryPage = () => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{through("resource-destroy") && (
|
||||
<i
|
||||
className="iconfont icon-icon-delete"
|
||||
style={{ fontSize: 24 }}
|
||||
onClick={() => removeItem(categories[id][i].id)}
|
||||
/>
|
||||
)}
|
||||
<i
|
||||
className="iconfont icon-icon-delete"
|
||||
style={{ fontSize: 24 }}
|
||||
onClick={() =>
|
||||
removeItem(categories[id][i].id, categories[id][i].name)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
@ -142,20 +142,24 @@ const ResourceCategoryPage = () => {
|
||||
setRefresh(!refresh);
|
||||
};
|
||||
|
||||
const removeItem = (id: number) => {
|
||||
const removeItem = (id: number, label: string) => {
|
||||
if (id === 0) {
|
||||
return;
|
||||
}
|
||||
resourceCategory.checkDestroy(id).then((res: any) => {
|
||||
if (
|
||||
res.data.children &&
|
||||
res.data.children.length === 0 &&
|
||||
res.data.courses &&
|
||||
res.data.courses.length === 0 &&
|
||||
res.data.images &&
|
||||
res.data.images.length === 0 &&
|
||||
res.data.videos &&
|
||||
res.data.videos.length === 0
|
||||
) {
|
||||
delUser(id);
|
||||
} else {
|
||||
if (res.data.children.length > 0) {
|
||||
if (res.data.children && res.data.children.length > 0) {
|
||||
modal.warning({
|
||||
title: "操作确认",
|
||||
centered: true,
|
||||
@ -178,32 +182,38 @@ const ResourceCategoryPage = () => {
|
||||
content: (
|
||||
<p>
|
||||
此分类已关联
|
||||
{res.data.courses.length > 0 && (
|
||||
{res.data.courses && res.data.courses.length > 0 && (
|
||||
<Button
|
||||
style={{ paddingLeft: 4, paddingRight: 4 }}
|
||||
type="link"
|
||||
danger
|
||||
onClick={() => navigate("/course")}
|
||||
onClick={() =>
|
||||
navigate("/course?cid=" + id + "&label=" + label)
|
||||
}
|
||||
>
|
||||
({res.data.courses.length}个线上课程),
|
||||
</Button>
|
||||
)}
|
||||
{res.data.videos.length > 0 && (
|
||||
{res.data.videos && res.data.videos.length > 0 && (
|
||||
<Button
|
||||
type="link"
|
||||
style={{ paddingLeft: 4, paddingRight: 4 }}
|
||||
danger
|
||||
onClick={() => navigate("/videos")}
|
||||
onClick={() =>
|
||||
navigate("/videos?cid=" + id + "&label=" + label)
|
||||
}
|
||||
>
|
||||
({res.data.videos.length}个视频文件),
|
||||
</Button>
|
||||
)}
|
||||
{res.data.images.length > 0 && (
|
||||
{res.data.images && res.data.images.length > 0 && (
|
||||
<Button
|
||||
type="link"
|
||||
style={{ paddingLeft: 4, paddingRight: 4 }}
|
||||
danger
|
||||
onClick={() => navigate("/images")}
|
||||
onClick={() =>
|
||||
navigate("/images?cid=" + id + "&label=" + label)
|
||||
}
|
||||
>
|
||||
({res.data.images.length}个图片文件),
|
||||
</Button>
|
||||
|
143
src/pages/resource/videos/compenents/update-dialog/index.tsx
Normal file
143
src/pages/resource/videos/compenents/update-dialog/index.tsx
Normal 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>
|
||||
</>
|
||||
);
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,12 +1,16 @@
|
||||
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 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 { dateFormat } from "../../../utils/index";
|
||||
import { TreeCategory, DurationText, PerButton } from "../../../compenents";
|
||||
import { UploadVideoButton } from "../../../compenents/upload-video-button";
|
||||
import { VideoPlayDialog } from "./compenents/video-play-dialog";
|
||||
import { VideosUpdateDialog } from "./compenents/update-dialog";
|
||||
|
||||
const { confirm } = Modal;
|
||||
|
||||
@ -18,6 +22,7 @@ interface DataType {
|
||||
}
|
||||
|
||||
const ResourceVideosPage = () => {
|
||||
const result = new URLSearchParams(useLocation().search);
|
||||
const [videoList, setVideoList] = useState<any>([]);
|
||||
const [videosExtra, setVideoExtra] = useState<any>([]);
|
||||
const [adminUsers, setAdminUsers] = useState<any>({});
|
||||
@ -27,21 +32,27 @@ const ResourceVideosPage = () => {
|
||||
const [total, setTotal] = useState(0);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
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> = [
|
||||
// {
|
||||
// title: "封面",
|
||||
// dataIndex: "id",
|
||||
// render: (id: string) => (
|
||||
// <Image
|
||||
// preview={false}
|
||||
// width={120}
|
||||
// height={80}
|
||||
// src={videosExtra[id].poster}
|
||||
// ></Image>
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
title: "视频名称",
|
||||
dataIndex: "name",
|
||||
@ -80,20 +91,68 @@ const ResourceVideosPage = () => {
|
||||
title: "操作",
|
||||
key: "action",
|
||||
fixed: "right",
|
||||
width: 100,
|
||||
render: (_, record: any) => (
|
||||
<Space size="small">
|
||||
<PerButton
|
||||
type="link"
|
||||
text="删除"
|
||||
class="b-link c-red"
|
||||
icon={null}
|
||||
p="resource-destroy"
|
||||
onClick={() => removeResource(record.id)}
|
||||
disabled={null}
|
||||
/>
|
||||
</Space>
|
||||
),
|
||||
width: 160,
|
||||
render: (_, record: any) => {
|
||||
const items: MenuProps["items"] = [
|
||||
{
|
||||
key: "1",
|
||||
label: (
|
||||
<Button
|
||||
type="link"
|
||||
className="b-link c-red"
|
||||
onClick={() => {
|
||||
setUpdateId(record.id);
|
||||
setUpdateVisible(true);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</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({
|
||||
title: "操作确认",
|
||||
icon: <ExclamationCircleFilled />,
|
||||
content: "确认删除此视频?",
|
||||
content: "删除前请检查选中视频文件无关联课程,确认删除?",
|
||||
centered: true,
|
||||
okText: "确认",
|
||||
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 = () => {
|
||||
setLoading(true);
|
||||
@ -138,11 +220,13 @@ const ResourceVideosPage = () => {
|
||||
console.log("错误,", err);
|
||||
});
|
||||
};
|
||||
|
||||
// 重置列表
|
||||
const resetVideoList = () => {
|
||||
setPage(1);
|
||||
setSize(10);
|
||||
setVideoList([]);
|
||||
setSelectedRowKeys([]);
|
||||
setRefresh(!refresh);
|
||||
};
|
||||
|
||||
@ -165,14 +249,22 @@ const ResourceVideosPage = () => {
|
||||
setSize(pageSize);
|
||||
};
|
||||
|
||||
const rowSelection = {
|
||||
onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
|
||||
setSelectedRowKeys(selectedRowKeys);
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="tree-main-body">
|
||||
<div className="left-box">
|
||||
<TreeCategory
|
||||
selected={category_ids}
|
||||
type="no-cate"
|
||||
text={"视频"}
|
||||
onUpdate={(keys: any, title: any) => {
|
||||
setPage(1);
|
||||
setCategoryIds(keys);
|
||||
if (typeof title === "string") {
|
||||
setLabel(title);
|
||||
@ -186,24 +278,74 @@ const ResourceVideosPage = () => {
|
||||
<div className="d-flex playedu-main-title float-left mb-24">
|
||||
视频 | {selLabel}
|
||||
</div>
|
||||
<div className="float-left mb-24">
|
||||
<UploadVideoButton
|
||||
categoryIds={category_ids}
|
||||
onUpdate={() => {
|
||||
resetVideoList();
|
||||
}}
|
||||
></UploadVideoButton>
|
||||
<div className="float-left j-b-flex mb-24">
|
||||
<div>
|
||||
<UploadVideoButton
|
||||
categoryIds={category_ids}
|
||||
onUpdate={() => {
|
||||
resetVideoList();
|
||||
}}
|
||||
></UploadVideoButton>
|
||||
</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">
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={videoList}
|
||||
loading={loading}
|
||||
pagination={paginationProps}
|
||||
rowKey={(record) => record.id}
|
||||
/>
|
||||
{multiConfig ? (
|
||||
<Table
|
||||
rowSelection={{
|
||||
type: "checkbox",
|
||||
...rowSelection,
|
||||
}}
|
||||
columns={columns}
|
||||
dataSource={videoList}
|
||||
loading={loading}
|
||||
pagination={paginationProps}
|
||||
rowKey={(record) => record.id}
|
||||
/>
|
||||
) : (
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={videoList}
|
||||
loading={loading}
|
||||
pagination={paginationProps}
|
||||
rowKey={(record) => record.id}
|
||||
/>
|
||||
)}
|
||||
</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>
|
||||
</>
|
||||
);
|
||||
|
@ -40,6 +40,7 @@ const SystemAdministratorPage = () => {
|
||||
const [role_ids, setRoleIds] = useState<any>([]);
|
||||
const [selLabel, setLabel] = useState<string>("全部管理员");
|
||||
const [roleDelSuccess, setRoleDelSuccess] = useState(false);
|
||||
const [isSuper, setIsSuper] = useState(false);
|
||||
|
||||
const [name, setName] = useState<string>("");
|
||||
|
||||
@ -216,9 +217,10 @@ const SystemAdministratorPage = () => {
|
||||
refresh={refresh}
|
||||
type=""
|
||||
text={"管理员"}
|
||||
onUpdate={(keys: any, title: any) => {
|
||||
onUpdate={(keys: any, title: any, isSuper: boolean) => {
|
||||
setRoleIds(keys);
|
||||
setLabel(title);
|
||||
setIsSuper(isSuper);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@ -248,7 +250,7 @@ const SystemAdministratorPage = () => {
|
||||
disabled={null}
|
||||
/>
|
||||
)}
|
||||
{role_ids.length > 0 && (
|
||||
{!isSuper && role_ids.length > 0 && (
|
||||
<>
|
||||
<PerButton
|
||||
text="角色权限"
|
||||
|
@ -72,11 +72,6 @@ export const SystemAdminrolesCreate: React.FC<PropInterface> = ({
|
||||
value: "线上课-n",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
title: "资源",
|
||||
value: "资源-n",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
title: "资源分类",
|
||||
value: "资源分类-n",
|
||||
@ -87,6 +82,11 @@ export const SystemAdminrolesCreate: React.FC<PropInterface> = ({
|
||||
value: "部门-n",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
title: "系统配置",
|
||||
value: "系统配置-n",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
title: "其它",
|
||||
value: "其它-n",
|
||||
|
@ -75,11 +75,6 @@ export const SystemAdminrolesUpdate: React.FC<PropInterface> = ({
|
||||
value: "线上课-n",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
title: "资源",
|
||||
value: "资源-n",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
title: "资源分类",
|
||||
value: "资源分类-n",
|
||||
@ -90,6 +85,11 @@ export const SystemAdminrolesUpdate: React.FC<PropInterface> = ({
|
||||
value: "部门-n",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
title: "系统配置",
|
||||
value: "系统配置-n",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
title: "其它",
|
||||
value: "其它-n",
|
||||
|
@ -52,6 +52,10 @@ const SystemConfigPage = () => {
|
||||
form.setFieldsValue({
|
||||
"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") {
|
||||
form.setFieldsValue({
|
||||
"system.pc_url": configData[i].key_value,
|
||||
@ -275,6 +279,13 @@ const SystemConfigPage = () => {
|
||||
</div>
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item
|
||||
style={{ marginBottom: 30 }}
|
||||
label="API访问地址"
|
||||
name="system.api_url"
|
||||
>
|
||||
<Input style={{ width: 274 }} placeholder="请填写API访问地址" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
style={{ marginBottom: 30 }}
|
||||
label="网站标题"
|
||||
@ -297,13 +308,7 @@ const SystemConfigPage = () => {
|
||||
placeholder="请填写网站页脚"
|
||||
/>
|
||||
</Form.Item>
|
||||
{/* <Form.Item
|
||||
style={{ marginBottom: 30 }}
|
||||
label="API访问地址"
|
||||
name="system.api_url"
|
||||
>
|
||||
<Input style={{ width: 274 }} placeholder="请填写API访问地址" />
|
||||
</Form.Item>
|
||||
{/*
|
||||
<Form.Item
|
||||
style={{ marginBottom: 30 }}
|
||||
label="PC端访问地址"
|
||||
@ -373,6 +378,14 @@ const SystemConfigPage = () => {
|
||||
style={{ width: 274 }}
|
||||
allowClear
|
||||
placeholder="自定义跑马灯内容"
|
||||
onChange={(e) => {
|
||||
const { value } = e.target;
|
||||
if (!value && e.type !== "change") {
|
||||
setNameChecked(false);
|
||||
setEmailChecked(false);
|
||||
setIdCardChecked(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Checkbox
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user