!14 存储桶改为private

* 后台 使用许可页面
* 优化:移除API访问地址配置
* 后台、pc、h5 删除无用配置
* docker部署优化
* 2.0 networkMode=bridge
* changelog
* 学员端权限为空报错
* h5 我的页面请求优化
* 缓存查询
* 后台 学员列表报错、线上课-上架时间字段优化
* 后台、pc、h5 使用签名地址
* 学员端接口修改
* 后台、pc 使用签名地址
* 后台 使用签名地址
* 上传接口
* 上传接口
* 系统配置
* 线上课封面
* bucket由public改为private
* 资源相关表实体及对象修改
* 统一数据库脚本
This commit is contained in:
白书科技
2025-05-22 07:23:06 +00:00
parent c206fa4bf2
commit 12daa31ab9
134 changed files with 10054 additions and 1231 deletions

View File

@@ -79,7 +79,7 @@ export function updateCourse(
category_ids: categoryIds,
chapters: chapters,
hours: hours,
published_at: publishedAt,
sort_at: publishedAt,
});
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -36,7 +36,7 @@ export const Footer: React.FC<PropInterface> = ({ type }) => {
className="ml-5"
style={{ color: "#D7D7D7", fontSize: 12, marginTop: -5 }}
>
Version 1.7
Version 2.0
</span>
</Link>
</Layout.Footer>

View File

@@ -96,6 +96,14 @@ const items = [
null,
null
),
getItem(
"使用许可",
"/licensing",
<i className="iconfont icon-xuke" />,
null,
null,
null,
),
];
export const LeftMenu: React.FC = () => {

View File

@@ -37,7 +37,7 @@ interface ImageItem {
interface PropsInterface {
text: any;
onSelected: (url: string) => void;
onSelected: (url: string, id: number) => void;
}
export const UploadImageButton = (props: PropsInterface) => {
@@ -50,6 +50,8 @@ export const UploadImageButton = (props: PropsInterface) => {
const [size, setSize] = useState(15);
const [total, setTotal] = useState(0);
const [selected, setSelected] = useState<string>("");
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [selectedKey, setSelectedKey] = useState<number>(0);
// 获取图片列表
const getImageList = () => {
@@ -59,6 +61,7 @@ export const UploadImageButton = (props: PropsInterface) => {
.then((res: any) => {
setTotal(res.data.result.total);
setImageList(res.data.result.data);
setResourceUrl(res.data.resource_url);
})
.catch((err) => {
console.log("错误,", err);
@@ -103,7 +106,7 @@ export const UploadImageButton = (props: PropsInterface) => {
message.error("请选择图片后确定");
return;
}
props.onSelected(selected);
props.onSelected(selected, selectedKey);
setShowModal(false);
}}
>
@@ -140,17 +143,19 @@ export const UploadImageButton = (props: PropsInterface) => {
<div
key={item.id}
className="image-item"
style={{ backgroundImage: `url(${item.url})` }}
style={{ backgroundImage: `url(${resourceUrl[item.id]})` }}
onClick={() => {
setSelected(item.url);
setSelected(resourceUrl[item.id]);
setSelectedKey(item.id);
}}
>
{selected.indexOf(item.url) !== -1 && (
{selected.indexOf(resourceUrl[item.id]) !== -1 && (
<i
className={styles.checked}
onClick={(e) => {
e.stopPropagation();
setSelected("");
setSelectedKey(0);
}}
>
<CheckOutlined />

View File

@@ -79,6 +79,10 @@ code {
margin-top: 10px;
}
.mt-16 {
margin-top: 16px;
}
.ml-15 {
margin-left: 15px;
}
@@ -123,6 +127,10 @@ code {
margin-right: 24px;
}
.mt-30 {
margin-top: 30px;
}
.mb-28 {
margin-bottom: 28px;
}
@@ -729,3 +737,7 @@ textarea.ant-input {
.clickable-stat:hover .ant-statistic-content {
color: #1890ff;
}
.ant-tree .ant-tree-switcher:before {
height: 40px;
}

View File

@@ -14,7 +14,6 @@ import {
Tag,
} from "antd";
import styles from "./create.module.less";
import { useSelector } from "react-redux";
import { course, department } from "../../../api/index";
import {
UploadImageButton,
@@ -25,6 +24,9 @@ import {
import { ExclamationCircleFilled } from "@ant-design/icons";
import { TreeHours } from "./hours";
import { TreeAttachments } from "./attachments";
import defaultThumb1 from "../../../assets/thumb/thumb1.png";
import defaultThumb2 from "../../../assets/thumb/thumb2.png";
import defaultThumb3 from "../../../assets/thumb/thumb3.png";
const { confirm } = Modal;
@@ -46,12 +48,6 @@ export const CourseCreate: React.FC<PropInterface> = ({
onCancel,
}) => {
const [form] = Form.useForm();
const courseDefaultThumbs = useSelector(
(state: any) => state.systemConfig.value.courseDefaultThumbs
);
const defaultThumb1 = courseDefaultThumbs[0];
const defaultThumb2 = courseDefaultThumbs[1];
const defaultThumb3 = courseDefaultThumbs[2];
const [loading, setLoading] = useState(false);
const [init, setInit] = useState(true);
const [departments, setDepartments] = useState<Option[]>([]);
@@ -85,7 +81,7 @@ export const CourseCreate: React.FC<PropInterface> = ({
useEffect(() => {
form.setFieldsValue({
title: "",
thumb: defaultThumb1,
thumb: -1,
isRequired: 1,
short_desc: "",
hasChapter: 0,
@@ -688,7 +684,7 @@ export const CourseCreate: React.FC<PropInterface> = ({
onClick={() => {
setThumb(defaultThumb1);
form.setFieldsValue({
thumb: defaultThumb1,
thumb: -1,
});
}}
>
@@ -709,7 +705,7 @@ export const CourseCreate: React.FC<PropInterface> = ({
onClick={() => {
setThumb(defaultThumb2);
form.setFieldsValue({
thumb: defaultThumb2,
thumb: -2,
});
}}
>
@@ -730,7 +726,7 @@ export const CourseCreate: React.FC<PropInterface> = ({
onClick={() => {
setThumb(defaultThumb3);
form.setFieldsValue({
thumb: defaultThumb3,
thumb: -3,
});
}}
>
@@ -746,9 +742,9 @@ export const CourseCreate: React.FC<PropInterface> = ({
<div className="d-flex">
<UploadImageButton
text="更换封面"
onSelected={(url) => {
onSelected={(url, id) => {
setThumb(url);
form.setFieldsValue({ thumb: url });
form.setFieldsValue({ thumb: id });
}}
></UploadImageButton>
<span className="helper-text ml-8">

View File

@@ -14,9 +14,11 @@ import {
Tag,
} from "antd";
import styles from "./update.module.less";
import { useSelector } from "react-redux";
import { course, department } from "../../../api/index";
import { UploadImageButton, SelectRange } from "../../../compenents";
import defaultThumb1 from "../../../assets/thumb/thumb1.png";
import defaultThumb2 from "../../../assets/thumb/thumb2.png";
import defaultThumb3 from "../../../assets/thumb/thumb3.png";
import dayjs from "dayjs";
import moment from "moment";
@@ -39,15 +41,10 @@ export const CourseUpdate: React.FC<PropInterface> = ({
}) => {
const [form] = Form.useForm();
const [init, setInit] = useState(true);
const courseDefaultThumbs = useSelector(
(state: any) => state.systemConfig.value.courseDefaultThumbs
);
const defaultThumb1 = courseDefaultThumbs[0];
const defaultThumb2 = courseDefaultThumbs[1];
const defaultThumb3 = courseDefaultThumbs[2];
const [loading, setLoading] = useState(false);
const [departments, setDepartments] = useState<Option[]>([]);
const [categories, setCategories] = useState<Option[]>([]);
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [thumb, setThumb] = useState("");
const [depIds, setDepIds] = useState<number[]>([]);
const [deps, setDeps] = useState<any[]>([]);
@@ -98,8 +95,8 @@ export const CourseUpdate: React.FC<PropInterface> = ({
short_desc: res.data.course.short_desc,
hasChapter: chapterType,
type: type,
published_at: res.data.course.published_at
? dayjs(res.data.course.published_at)
published_at: res.data.course.sort_at
? dayjs(res.data.course.sort_at)
: "",
});
setType(type);
@@ -111,6 +108,16 @@ export const CourseUpdate: React.FC<PropInterface> = ({
if (deps && JSON.stringify(deps) !== "{}") {
form.setFieldsValue({ ids: [1, 2] });
}
setResourceUrl(res.data.resource_url);
setThumb(
res.data.course.thumb === -1
? defaultThumb1
: res.data.course.thumb === -2
? defaultThumb2
: res.data.course.thumb === -3
? defaultThumb3
: res.data.resource_url[res.data.course.thumb]
);
setInit(false);
});
};
@@ -412,7 +419,7 @@ export const CourseUpdate: React.FC<PropInterface> = ({
onClick={() => {
setThumb(defaultThumb1);
form.setFieldsValue({
thumb: defaultThumb1,
thumb: -1,
});
}}
>
@@ -433,7 +440,7 @@ export const CourseUpdate: React.FC<PropInterface> = ({
onClick={() => {
setThumb(defaultThumb2);
form.setFieldsValue({
thumb: defaultThumb2,
thumb: -2,
});
}}
>
@@ -454,7 +461,7 @@ export const CourseUpdate: React.FC<PropInterface> = ({
onClick={() => {
setThumb(defaultThumb3);
form.setFieldsValue({
thumb: defaultThumb3,
thumb: -3,
});
}}
>
@@ -470,9 +477,9 @@ export const CourseUpdate: React.FC<PropInterface> = ({
<div className="d-flex">
<UploadImageButton
text="更换封面"
onSelected={(url) => {
onSelected={(url, id) => {
setThumb(url);
form.setFieldsValue({ thumb: url });
form.setFieldsValue({ thumb: id });
}}
></UploadImageButton>
<span className="helper-text ml-8">

View File

@@ -27,6 +27,9 @@ import { CourseCreate } from "./compenents/create";
import { CourseUpdate } from "./compenents/update";
import { CourseHourUpdate } from "./compenents/hour-update";
import { CourseAttachmentUpdate } from "./compenents/attachment-update";
import defaultThumb1 from "../../assets/thumb/thumb1.png";
import defaultThumb2 from "../../assets/thumb/thumb2.png";
import defaultThumb3 from "../../assets/thumb/thumb3.png";
const { confirm } = Modal;
@@ -77,6 +80,7 @@ const CoursePage = () => {
useState<CategoryIdsModel>({});
const [course_dep_ids, setCourseDepIds] = useState<DepIdsModel>({});
const [categories, setCategories] = useState<CategoriesModel>({});
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [departments, setDepartments] = useState<DepartmentsModel>({});
const [tabKey, setTabKey] = useState(result.get("did") ? "2" : "1");
const [adminUsers, setAdminUsers] = useState<any>({});
@@ -166,7 +170,15 @@ const CoursePage = () => {
width={80}
height={60}
style={{ borderRadius: 6 }}
src={record.thumb}
src={
record.thumb === -1
? defaultThumb1
: record.thumb === -2
? defaultThumb2
: record.thumb === -3
? defaultThumb3
: resourceUrl[record.thumb]
}
></Image>
<span className="ml-8">{record.title}</span>
</div>
@@ -227,7 +239,7 @@ const CoursePage = () => {
},
{
title: "上架时间",
dataIndex: "published_at",
dataIndex: "sort_at",
render: (text: string) => <span>{dateFormat(text)}</span>,
},
{
@@ -381,6 +393,7 @@ const CoursePage = () => {
setCategories(res.data.categories);
setDepartments(res.data.departments);
setAdminUsers(res.data.admin_users);
setResourceUrl(res.data.resource_url)
setLoading(false);
})
.catch((err: any) => {

View File

@@ -17,6 +17,7 @@ import { BackBartment } from "../../compenents";
import { ExclamationCircleFilled } from "@ant-design/icons";
import { PerButton } from "../../compenents";
import { dateFormat } from "../../utils/index";
import memberDefaultAvatar from "../../assets/thumb/avatar.png";
const { confirm } = Modal;
@@ -95,6 +96,7 @@ const CourseUserPage = () => {
const [email, setEmail] = useState("");
const [idCard, setIdCard] = useState("");
const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [title, setTitle] = useState<string>(String(result.get("title")));
const columns: ColumnsType<DataType> = [
@@ -107,7 +109,11 @@ const CourseUserPage = () => {
preview={false}
width={40}
height={40}
src={record.avatar}
src={
record.avatar == -1
? memberDefaultAvatar
: resourceUrl[record.avatar]
}
></Image>
<span className="ml-8">{record.name}</span>
</div>
@@ -231,6 +237,7 @@ const CourseUserPage = () => {
setHourCount(res.data.user_course_hour_user_first_at);
setRecords(res.data.user_course_records);
setPerRecords(res.data.per_user_earliest_records);
setResourceUrl(res.data.resource_url);
setCourse(res.data.course);
setDepartments(res.data.departments);
setUserDepIds(res.data.user_dep_ids);

View File

@@ -23,9 +23,9 @@ const InitPage = (props: Props) => {
"ldap-enabled": props.configData["ldap-enabled"],
systemName: props.configData["system.name"],
systemLogo: props.configData["system.logo"],
systemApiUrl: props.configData["system.api_url"],
systemPcUrl: props.configData["system.pc_url"],
systemH5Url: props.configData["system.h5_url"],
resourceUrl: props.configData["resource_url"],
memberDefaultAvatar: props.configData["member.default_avatar"],
courseDefaultThumbs: props.configData["default.course_thumbs"],
departments: props.configData["departments"],

View File

@@ -0,0 +1,194 @@
.main-title {
width: 100%;
height: auto;
float: left;
font-weight: 500;
font-size: 18px;
color: #333333;
line-height: 24px;
text-align: left;
font-style: normal;
text-transform: none;
}
.persion {
width: 158px;
height: 32px;
background: rgba(255, 77, 79, 0.1);
border-radius: 6px 6px 6px 6px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 400;
font-size: 14px;
color: #ff4d4f;
}
.content {
width: 100%;
height: auto;
float: left;
font-weight: 400;
font-size: 14px;
color: #666666;
line-height: 24px;
text-align: left;
}
.contrast-box1 {
width: 100%;
height: 85px;
float: left;
background: #fafafa;
border-radius: 16px;
box-sizing: border-box;
-moz-box-sizing: border-box;
/* Firefox */
-webkit-box-sizing: border-box;
/* Safari */
padding: 15px 100px 15px 100px;
display: flex;
align-items: center;
.name {
flex: 1;
height: 25px;
font-size: 18px;
font-weight: 600;
color: rgba(0, 0, 0, 0.88);
line-height: 25px;
}
.ex {
width: 114px;
height: 55px;
background: #ff4d4f;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 600;
color: #ffffff;
line-height: 25px;
margin-right: 307px;
}
.ex2 {
width: 114px;
height: 55px;
background: #f1aa2e;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 600;
color: #ffffff;
line-height: 25px;
margin-right: 47px;
}
}
.contrast-box2 {
width: 100%;
float: left;
height: 65px;
background: rgba(#f1aa2e, 0.1);
border-radius: 16px 16px 0px 0px;
box-sizing: border-box;
-moz-box-sizing: border-box;
/* Firefox */
-webkit-box-sizing: border-box;
/* Safari */
padding: 20px 100px 20px 100px;
display: flex;
align-items: center;
.name {
flex: 1;
height: 25px;
font-weight: 600;
font-size: 18px;
color: rgba(0, 0, 0, 0.88);
line-height: 25px;
}
}
.contrast-box3 {
width: 100%;
height: 85px;
float: left;
height: 76px;
border: 1px solid rgba(0, 0, 0, 0.05);
box-sizing: border-box;
-moz-box-sizing: border-box;
/* Firefox */
-webkit-box-sizing: border-box;
/* Safari */
padding: 30px 100px 30px 100px;
display: flex;
align-items: center;
border-top: none;
position: relative;
.name {
flex: 1;
height: 16px;
display: flex;
align-items: center;
strong {
width: 8px;
height: 8px;
background: #f1aa2e;
border-radius: 50%;
margin-right: 10px;
}
span {
font-weight: 400;
font-size: 16px;
color: #333333;
line-height: 16px;
}
.sp {
font-size: 14px;
font-weight: 400;
color: rgba(0, 0, 0, 0.45);
line-height: 16px;
}
}
.ex {
width: 209px;
height: auto;
text-align: center;
font-weight: 400;
font-size: 14px;
color: #ff4d4f;
line-height: 16px;
margin-right: 209px;
display: flex;
align-items: center;
justify-content: center;
.pic {
width: 18px;
height: 18px;
}
}
.ex2 {
width: 209px;
height: auto;
text-align: center;
font-weight: 400;
font-size: 14px;
color: #ff9900;
line-height: 16px;
display: flex;
align-items: center;
justify-content: center;
.pic {
width: 18px;
height: 18px;
}
}
}
.icon {
width: 16px;
height: 16px;
margin-right: 5px;
}

View File

@@ -0,0 +1,826 @@
import styles from "./index.module.less";
import { Button, Tooltip } from "antd";
import fangIcon from "../../assets/images/commen/fanghu.png";
import ex1Icon from "../../assets/images/commen/icon5.png";
import ex2Icon from "../../assets/images/commen/icon6.png";
const LicensingPage = () => {
return (
<>
<div className="playedu-main-top">
<div className={styles["main-title"]}></div>
<div className="float-left mt-24">
<div className={styles["persion"]}>PlayEdu开源版 v2.0</div>
</div>
<div className="float-left mt-16">
<div className={styles["content"]}>
1.PlayEdu开源版版权归杭州白书科技有限公司所有使
</div>
<div className={styles["content"]}>
2.
</div>
<div className={styles["content"]}>
3.
PlayEdu开源版页面及代码中的原有版权信息 Designed By PlayEdu
</div>
</div>
<div className="float-left mt-24">
<Button
type="primary"
onClick={() => {
window.open("https://www.playeduos.com/");
}}
>
</Button>
</div>
</div>
<div className="playedu-main-top mt-24" style={{ position: "relative" }}>
<div className={styles["main-title"]}></div>
<div className="float-left mt-24">
<div className={styles["contrast-box1"]}>
<div className={styles["name"]}></div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}></div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<Tooltip
className={styles["ex2"]}
title="专属售后群以及远程排障服务"
>
<img src={fangIcon} className={styles["icon"]} />
7*10h专业技术服务
</Tooltip>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>CMA国家资质安全认证</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}></div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}></div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>MP4(H264)</div>
<div className={styles["ex2"]}>MP4|MOV|AVI|WMV|FLV</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
<span className={styles["sp"]}></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
<span className={styles["sp"]}>
WordPPTPDF在线预览
</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
<span className={styles["sp"]}></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
<span className={styles["sp"]}>
</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
<span className={styles["sp"]}></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>线</span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>线</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
<span className={styles["sp"]}>
</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
<span className={styles["sp"]}>
/
</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>||</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>LDAP</span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>CAS</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}></div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}></div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>MinIO()</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>oss</span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span>cos</span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>HLS视频加密</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>PC独立网站</span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span>H5</span>
</div>
<div className={styles["ex"]}>
<img src={ex1Icon} className={styles["pic"]} />
</div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}></div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}></div>
</div>
</div>
<div className="float-left mt-30">
<div className={styles["contrast-box2"]}>
<div className={styles["name"]}></div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span>使</span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div className={styles["contrast-box3"]}>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
<div
className={styles["contrast-box3"]}
style={{ borderRadius: "0px 0px 16px 16px" }}
>
<div className={styles["name"]}>
<strong></strong>
<span></span>
</div>
<div className={styles["ex"]}></div>
<div className={styles["ex2"]}>
<img src={ex2Icon} className={styles["pic"]} />
</div>
</div>
</div>
</div>
</>
);
};
export default LicensingPage;

View File

@@ -63,9 +63,9 @@ const LoginPage = () => {
"ldap-enabled": res.data["ldap-enabled"],
systemName: res.data["system.name"],
systemLogo: res.data["system.logo"],
systemApiUrl: res.data["system.api_url"],
systemPcUrl: res.data["system.pc_url"],
systemH5Url: res.data["system.h5_url"],
resourceUrl: res.data["resource_url"],
memberDefaultAvatar: res.data["member.default_avatar"],
courseDefaultThumbs: res.data["default.course_thumbs"],
departments: res.data["departments"],

View File

@@ -5,6 +5,7 @@ import { useSelector } from "react-redux";
import { user, department } from "../../../api/index";
import { UploadImageButton } from "../../../compenents";
import { ValidataCredentials } from "../../../utils/index";
import memberDefaultAvatar from "../../../assets/thumb/avatar.png";
interface PropInterface {
open: boolean;
@@ -27,9 +28,12 @@ export const MemberCreate: React.FC<PropInterface> = ({
const [init, setInit] = useState(true);
const [loading, setLoading] = useState(false);
const [departments, setDepartments] = useState<any>([]);
const memberDefaultAvatar = useSelector(
const systemMemberDefaultAvatar = useSelector(
(state: any) => state.systemConfig.value.memberDefaultAvatar
);
const systemResourceUrl = useSelector(
(state: any) => state.systemConfig.value.resourceUrl
);
const [avatar, setAvatar] = useState<string>(memberDefaultAvatar);
useEffect(() => {
@@ -44,11 +48,20 @@ export const MemberCreate: React.FC<PropInterface> = ({
email: "",
name: "",
password: "",
avatar: memberDefaultAvatar,
avatar: systemMemberDefaultAvatar
? Number(systemMemberDefaultAvatar)
: -1,
idCard: "",
dep_ids: depIds,
});
setAvatar(memberDefaultAvatar);
if (systemMemberDefaultAvatar === -1) {
setAvatar(memberDefaultAvatar);
} else if (systemMemberDefaultAvatar >= 0) {
setAvatar(systemResourceUrl[Number(systemMemberDefaultAvatar)]);
} else {
setAvatar(memberDefaultAvatar);
}
}, [form, open, depIds]);
const getParams = () => {
@@ -160,9 +173,9 @@ export const MemberCreate: React.FC<PropInterface> = ({
<div className="d-flex">
<UploadImageButton
text="更换头像"
onSelected={(url) => {
onSelected={(url, id) => {
setAvatar(url);
form.setFieldsValue({ avatar: url });
form.setFieldsValue({ avatar: id });
}}
></UploadImageButton>
</div>

View File

@@ -1,10 +1,10 @@
import React, { useState, useEffect } from "react";
import { Modal, Form, TreeSelect, Input, message, Spin } from "antd";
import styles from "./update.module.less";
import { useSelector } from "react-redux";
import { user, department } from "../../../api/index";
import { UploadImageButton } from "../../../compenents";
import { ValidataCredentials } from "../../../utils/index";
import memberDefaultAvatar from "../../../assets/thumb/avatar.png";
interface PropInterface {
id: number;
@@ -27,9 +27,7 @@ export const MemberUpdate: React.FC<PropInterface> = ({
const [init, setInit] = useState(true);
const [loading, setLoading] = useState(false);
const [departments, setDepartments] = useState<any>([]);
const memberDefaultAvatar = useSelector(
(state: any) => state.systemConfig.value.memberDefaultAvatar
);
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [avatar, setAvatar] = useState<string>(memberDefaultAvatar);
useEffect(() => {
@@ -62,7 +60,7 @@ export const MemberUpdate: React.FC<PropInterface> = ({
const getDetail = () => {
user.user(id).then((res: any) => {
let user = res.data.user;
setAvatar(user.avatar);
setResourceUrl(res.data.resource_url);
form.setFieldsValue({
email: user.email,
name: user.name,
@@ -70,6 +68,11 @@ export const MemberUpdate: React.FC<PropInterface> = ({
idCard: user.id_card,
dep_ids: res.data.dep_ids,
});
if (user.avatar === -1) {
setAvatar(memberDefaultAvatar);
} else {
setAvatar(res.data.resource_url[user.avatar]);
}
setInit(false);
});
};
@@ -185,9 +188,9 @@ export const MemberUpdate: React.FC<PropInterface> = ({
<div className="d-flex">
<UploadImageButton
text="更换头像"
onSelected={(url) => {
onSelected={(url, id) => {
setAvatar(url);
form.setFieldsValue({ avatar: url });
form.setFieldsValue({ avatar: id });
}}
></UploadImageButton>
</div>

View File

@@ -25,6 +25,7 @@ import { useSelector } from "react-redux";
import { TreeDepartment, PerButton } from "../../compenents";
import { MemberCreate } from "./compenents/create";
import { MemberUpdate } from "./compenents/update";
import memberDefaultAvatar from "../../assets/thumb/avatar.png";
const { confirm } = Modal;
interface DataType {
@@ -69,6 +70,7 @@ const MemberPage = () => {
const [loading, setLoading] = useState(false);
const [list, setList] = useState<DataType[]>([]);
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [total, setTotal] = useState(0);
const [refresh, setRefresh] = useState(false);
const [dep_ids, setDepIds] = useState<number[]>([]);
@@ -103,7 +105,11 @@ const MemberPage = () => {
<>
<Image
style={{ borderRadius: "50%" }}
src={record.avatar}
src={
record.avatar == -1
? memberDefaultAvatar
: resourceUrl[record.avatar]
}
preview={false}
width={40}
height={40}
@@ -250,6 +256,7 @@ const MemberPage = () => {
setList(res.data.data);
setDepartments(res.data.departments);
setUserDepIds(res.data.user_dep_ids);
setResourceUrl(res.data.resource_url);
setTotal(res.data.total);
setLoading(false);
});

View File

@@ -8,6 +8,9 @@ import { user as member } from "../../api/index";
import * as echarts from "echarts";
import type { ColumnsType } from "antd/es/table";
import { MemberLearnProgressDialog } from "./compenents/progress";
import defaultThumb1 from "../../assets/thumb/thumb1.png";
import defaultThumb2 from "../../assets/thumb/thumb2.png";
import defaultThumb3 from "../../assets/thumb/thumb3.png";
interface DataType {
id: React.Key;
@@ -87,6 +90,7 @@ const MemberLearnPage = () => {
const [records, setRecords] = useState<UserCourseRecordsModel>({});
const [perRecords, setPerRecords] = useState<PerCourseRecordsModel>({});
const [hourCount, setHourCount] = useState<HourCountModel>({});
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [total2, setTotal2] = useState(0);
const [refresh2, setRefresh2] = useState(false);
const [uid, setUid] = useState(Number(result.get("id")));
@@ -212,6 +216,7 @@ const MemberLearnPage = () => {
setHourCount(res.data.user_course_hour_count);
setRecords(res.data.user_course_records);
setPerRecords(res.data.per_course_earliest_records);
setResourceUrl(res.data.resource_url);
if (res.data.departments.length > 0) {
let box: OptionModel[] = [];
res.data.departments.map((item: any) => {
@@ -236,13 +241,31 @@ const MemberLearnPage = () => {
dataIndex: "title",
render: (_, record: any) => (
<div className="d-flex">
<Image
src={record.thumb}
preview={false}
width={80}
height={60}
style={{ borderRadius: 6 }}
/>
{loading2 ? (
<Image
src={defaultThumb1}
preview={false}
width={80}
height={60}
style={{ borderRadius: 6 }}
/>
) : (
<Image
src={
record.thumb === -1
? defaultThumb1
: record.thumb === -2
? defaultThumb2
: record.thumb === -3
? defaultThumb3
: resourceUrl[record.thumb]
}
preview={false}
width={80}
height={60}
style={{ borderRadius: 6 }}
/>
)}
<span className="ml-8">{record.title}</span>
</div>
),

View File

@@ -43,6 +43,7 @@ const ResourceCoursewarePage = () => {
const [list, setList] = useState<DataType[]>([]);
const [adminUsers, setAdminUsers] = useState<AdminUsersModel>({});
const [existingTypes, setExistingTypes] = useState<string[]>([]);
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [refresh, setRefresh] = useState(false);
const [page, setPage] = useState(1);
const [size, setSize] = useState(10);
@@ -94,6 +95,7 @@ const ResourceCoursewarePage = () => {
setList(res.data.result.data);
setExistingTypes(res.data.existing_types);
setAdminUsers(res.data.admin_users);
setResourceUrl(res.data.resource_url);
setLoading(false);
})
.catch((err: any) => {
@@ -153,7 +155,11 @@ const ResourceCoursewarePage = () => {
size="small"
className="b-n-link c-red"
onClick={() => {
downLoadFile(record.url);
downLoadFile(
resourceUrl[record.id],
record.name,
record.extension
);
}}
>
@@ -262,9 +268,17 @@ const ResourceCoursewarePage = () => {
});
};
const downLoadFile = (url: string) => {
console.log(url);
const downLoadFile = (url: string, name: string, extension: string) => {
window.open(url);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
a.download = `${name}.${extension}`; // 设置下载的文件名
document.body.appendChild(a);
a.click(); // 触发点击事件
// 释放 URL 对象
URL.revokeObjectURL(url);
document.body.removeChild(a);
};
return (

View File

@@ -35,6 +35,7 @@ interface ImageItem {
const ResourceImagesPage = () => {
const result = new URLSearchParams(useLocation().search);
const [imageList, setImageList] = useState<ImageItem[]>([]);
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [refresh, setRefresh] = useState(false);
const [page, setPage] = useState(1);
const [size, setSize] = useState(32);
@@ -96,6 +97,7 @@ const ResourceImagesPage = () => {
.then((res: any) => {
setTotal(res.data.result.total);
setImageList(res.data.result.data);
setResourceUrl(res.data.resource_url);
let data: ImageItem[] = res.data.result.data;
let arr = [];
for (let i = 0; i < data.length; i++) {
@@ -232,7 +234,7 @@ const ResourceImagesPage = () => {
<div
key={item.id}
className={`${styles.imageItem} ref-image-item`}
style={{ backgroundImage: `url(${item.url})` }}
style={{ backgroundImage: `url(${resourceUrl[item.id]})` }}
onClick={() => showImage(index, true)}
onMouseOver={() => showHover(index, true)}
onMouseOut={() => showHover(index, false)}
@@ -254,10 +256,10 @@ const ResourceImagesPage = () => {
<Image
width={200}
style={{ display: "none" }}
src={item.url}
src={resourceUrl[item.id]}
preview={{
visible: visibleArr[index],
src: item.url,
src: resourceUrl[item.id],
onVisibleChange: (value) => {
showImage(index, value);
},

View File

@@ -56,6 +56,7 @@ const ResourceVideosPage = () => {
const [videoList, setVideoList] = useState<DataType[]>([]);
const [videosExtra, setVideoExtra] = useState<VideosExtraModel>({});
const [adminUsers, setAdminUsers] = useState<AdminUsersModel>({});
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [refresh, setRefresh] = useState(false);
const [page, setPage] = useState(1);
const [size, setSize] = useState(10);
@@ -164,7 +165,7 @@ const ResourceVideosPage = () => {
className="b-n-link c-red"
onClick={() => {
setUpdateId(record.id);
setPlayUrl(record.url);
setPlayUrl(resourceUrl[record.id]);
setPlayeVisible(true);
}}
>
@@ -247,6 +248,7 @@ const ResourceVideosPage = () => {
setVideoList(res.data.result.data);
setVideoExtra(res.data.videos_extra);
setAdminUsers(res.data.admin_users);
setResourceUrl(res.data.resource_url);
setLoading(false);
})
.catch((err: any) => {

View File

@@ -15,7 +15,7 @@ import {
} from "antd";
import { appConfig, system } from "../../../api/index";
import { UploadImageButton } from "../../../compenents";
import { useSelector, useDispatch } from "react-redux";
import { useDispatch } from "react-redux";
import type { TabsProps } from "antd";
import type { CheckboxChangeEvent } from "antd/es/checkbox";
import {
@@ -23,6 +23,7 @@ import {
saveConfigAction,
} from "../../../store/system/systemConfigSlice";
import logoIcon from "../../../assets/logo.png";
import memberDefaultAvatar from "../../../assets/thumb/avatar.png";
const SystemConfigPage = () => {
const dispatch = useDispatch();
@@ -32,13 +33,10 @@ const SystemConfigPage = () => {
const [thumb, setThumb] = useState("");
const [avatar, setAvatar] = useState("");
const [tabKey, setTabKey] = useState(1);
const [s3Service, setS3Service] = useState("");
const [resourceUrl, setResourceUrl] = useState<ResourceUrlModel>({});
const [nameChecked, setNameChecked] = useState(false);
const [emailChecked, setEmailChecked] = useState(false);
const [idCardchecked, setIdCardChecked] = useState(false);
const memberDefaultAvatar = useSelector(
(state: any) => state.systemConfig.value.memberDefaultAvatar
);
useEffect(() => {
getDetail();
@@ -46,7 +44,8 @@ const SystemConfigPage = () => {
const getDetail = () => {
appConfig.appConfig().then((res: any) => {
let configData = res.data;
setResourceUrl(res.data.resource_url);
let configData = res.data.app_config;
for (let i = 0; i < configData.length; i++) {
if (configData[i].key_name === "system.name") {
form.setFieldsValue({
@@ -56,19 +55,12 @@ const SystemConfigPage = () => {
form.setFieldsValue({
"system.logo": configData[i].key_value,
});
console.log(configData[i].key_value);
if (configData[i].key_value !== "") {
setLogo(configData[i].key_value);
setLogo(res.data.resource_url[Number(configData[i].key_value)]);
} else {
setLogo(logoIcon);
}
} 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.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,
@@ -78,7 +70,9 @@ const SystemConfigPage = () => {
"system.h5_url": configData[i].key_value,
});
} else if (configData[i].key_name === "player.poster") {
setThumb(configData[i].key_value);
if (configData[i].key_value !== "") {
setThumb(res.data.resource_url[Number(configData[i].key_value)]);
}
form.setFieldsValue({
"player.poster": configData[i].key_value,
});
@@ -131,18 +125,13 @@ const SystemConfigPage = () => {
});
} else if (configData[i].key_name === "member.default_avatar") {
if (configData[i].key_value !== "") {
setAvatar(configData[i].key_value);
setAvatar(res.data.resource_url[Number(configData[i].key_value)]);
} else {
setAvatar(memberDefaultAvatar);
}
form.setFieldsValue({
"member.default_avatar": configData[i].key_value,
});
} else if (configData[i].key_name === "s3.service") {
form.setFieldsValue({
"s3.service": configData[i].key_value,
});
setS3Service(configData[i].key_value);
} else if (configData[i].key_name === "s3.access_key") {
form.setFieldsValue({
"s3.access_key": configData[i].key_value,
@@ -163,10 +152,6 @@ const SystemConfigPage = () => {
form.setFieldsValue({
"s3.endpoint": configData[i].key_value,
});
} else if (configData[i].key_name === "s3.domain") {
form.setFieldsValue({
"s3.domain": configData[i].key_value,
});
} else if (configData[i].key_name === "ldap.enabled") {
let value = 0;
if (configData[i].key_value === "1") {
@@ -271,7 +256,6 @@ const SystemConfigPage = () => {
"ldap-enabled": res.data["ldap-enabled"],
systemName: res.data["system.name"],
systemLogo: res.data["system.logo"],
systemApiUrl: res.data["system.api_url"],
systemPcUrl: res.data["system.pc_url"],
systemH5Url: res.data["system.h5_url"],
memberDefaultAvatar: res.data["member.default_avatar"],
@@ -322,9 +306,9 @@ const SystemConfigPage = () => {
<div className="d-flex ml-24">
<UploadImageButton
text="更换Logo"
onSelected={(url) => {
onSelected={(url, id) => {
setLogo(url);
form.setFieldsValue({ "system.logo": url });
form.setFieldsValue({ "system.logo": id });
}}
></UploadImageButton>
</div>
@@ -344,9 +328,9 @@ const SystemConfigPage = () => {
<div className="d-flex ml-24">
<UploadImageButton
text="更换Logo"
onSelected={(url) => {
onSelected={(url, id) => {
setLogo(url);
form.setFieldsValue({ "system.logo": url });
form.setFieldsValue({ "system.logo": id });
}}
></UploadImageButton>
</div>
@@ -356,13 +340,6 @@ 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="PC学员端地址"
@@ -511,9 +488,9 @@ const SystemConfigPage = () => {
<div className="d-flex ml-24">
<UploadImageButton
text="更换封面"
onSelected={(url) => {
onSelected={(url, id) => {
setThumb(url);
form.setFieldsValue({ "player.poster": url });
form.setFieldsValue({ "player.poster": id });
}}
></UploadImageButton>
<div className="helper-text ml-8">
@@ -533,9 +510,9 @@ const SystemConfigPage = () => {
<div className="d-flex">
<UploadImageButton
text="更换封面"
onSelected={(url) => {
onSelected={(url, id) => {
setThumb(url);
form.setFieldsValue({ "player.poster": url });
form.setFieldsValue({ "player.poster": id });
}}
></UploadImageButton>
<div className="helper-text ml-8">
@@ -588,9 +565,9 @@ const SystemConfigPage = () => {
<div className="d-flex ml-24">
<UploadImageButton
text="更换头像"
onSelected={(url) => {
onSelected={(url, id) => {
setAvatar(url);
form.setFieldsValue({ "member.default_avatar": url });
form.setFieldsValue({ "member.default_avatar": id });
}}
></UploadImageButton>
<div className="helper-text ml-8"></div>
@@ -608,9 +585,9 @@ const SystemConfigPage = () => {
<div className="d-flex">
<UploadImageButton
text="更换头像"
onSelected={(url) => {
onSelected={(url, id) => {
setAvatar(url);
form.setFieldsValue({ "member.default_avatar": url });
form.setFieldsValue({ "member.default_avatar": id });
}}
></UploadImageButton>
<div className="helper-text ml-8"></div>
@@ -643,24 +620,6 @@ const SystemConfigPage = () => {
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
style={{ marginBottom: 30 }}
label="服务商"
name="s3.service"
>
<Select
defaultValue={null}
style={{ width: 200 }}
placeholder="请选择服务商"
options={[
{ value: "oss", label: "阿里云OSS" },
{ value: "cos", label: "腾讯云COS" },
]}
onChange={(e: any) => {
setS3Service(e);
}}
/>
</Form.Item>
<Form.Item
style={{ marginBottom: 30 }}
label="AccessKey"
@@ -716,17 +675,6 @@ const SystemConfigPage = () => {
placeholder="请填写Endpoint"
/>
</Form.Item>
<Form.Item
style={{ marginBottom: 30 }}
label="Domain"
name="s3.domain"
>
<Input
style={{ width: 274 }}
allowClear
placeholder="请填写Domain"
/>
</Form.Item>
<Form.Item
style={{ marginBottom: 30 }}
wrapperCol={{ offset: 3, span: 21 }}

View File

@@ -141,6 +141,10 @@ declare global {
rid: number;
type: string;
}
interface ResourceUrlModel {
[key: number]: string;
}
}
export {};

View File

@@ -46,6 +46,8 @@ const DepartmentPage = lazy(() => import("../pages/department"));
const TestPage = lazy(() => import("../pages/test"));
//错误页面
const ErrorPage = lazy(() => import("../pages/error"));
//使用许可页面
const LicensingPage = lazy(() => import("../pages/licensing/index"));
import PrivateRoute from "../compenents/private-route";
@@ -161,6 +163,10 @@ const routes: RouteObject[] = [
path: "/department",
element: <PrivateRoute Component={<DepartmentPage />} />,
},
{
path: "/licensing",
element: <PrivateRoute Component={<LicensingPage />} />,
},
],
},
{

View File

@@ -2,7 +2,6 @@ import { createSlice } from "@reduxjs/toolkit";
type SystemConfigStoreInterface = {
"ldap-enabled"?: boolean;
systemApiUrl?: string;
systemPcUrl?: string;
systemH5Url?: string;
systemLogo?: string;
@@ -11,6 +10,7 @@ type SystemConfigStoreInterface = {
courseDefaultThumbs?: string[];
departments?: any;
resourceCategories?: any;
resourceUrl?: ResourceUrlModel;
};
let defaultValue: SystemConfigStoreInterface = {};