Commit d146a050 authored by krysent's avatar krysent

ccc

parent 480ef123
...@@ -41,7 +41,7 @@ const EditTable = (props) => { ...@@ -41,7 +41,7 @@ const EditTable = (props) => {
} }
const result = await doFetch({ url: path, params: newparams }); const result = await doFetch({ url: path, params: newparams });
//分页结果 //分页结果
let data = result?.data?.page?.list, let data = result?.data?.page?.records,
success = true, success = true,
total = result?.data?.page?.total; total = result?.data?.page?.total;
//不带分页获取结果 //不带分页获取结果
......
...@@ -85,8 +85,8 @@ let FormRender = memo(({ fields = [], colProps, proformRef }) => { ...@@ -85,8 +85,8 @@ let FormRender = memo(({ fields = [], colProps, proformRef }) => {
function InitForm({ function InitForm({
formRef, formRef,
onFinish = (vals,extra) => { onFinish = (vals, extra) => {
console.log(vals,extra); console.log(vals, extra);
}, },
formKey, formKey,
params = {}, params = {},
...@@ -115,6 +115,7 @@ function InitForm({ ...@@ -115,6 +115,7 @@ function InitForm({
? submitter ? submitter
: { : {
render: (props, doms) => { render: (props, doms) => {
console.log("submitterProps", props);
return [ return [
<Button <Button
type="reset" type="reset"
...@@ -127,7 +128,10 @@ function InitForm({ ...@@ -127,7 +128,10 @@ function InitForm({
type="submit" type="submit"
key="submit" key="submit"
variant="contained" variant="contained"
onClick={() => props.form?.submit?.()} onClick={(e) => {
e.preventDefault();
return props.form?.submit?.()
}}
> >
提交 提交
</Button>, </Button>,
......
...@@ -39,7 +39,7 @@ ShopProductCard.propTypes = { ...@@ -39,7 +39,7 @@ ShopProductCard.propTypes = {
product: PropTypes.object, product: PropTypes.object,
}; };
export default function ShopProductCard({ product, remove, edit, publish }) { export default function ShopProductCard({ product, remove, edit, publish,authorized }) {
const { courseName, picUrl, createTime, statusName, type } = product; const { courseName, picUrl, createTime, statusName, type } = product;
const [confirm, setconfirm] = useState(false); const [confirm, setconfirm] = useState(false);
const [shut, setshut] = useState(false); const [shut, setshut] = useState(false);
...@@ -143,7 +143,11 @@ export default function ShopProductCard({ product, remove, edit, publish }) { ...@@ -143,7 +143,11 @@ export default function ShopProductCard({ product, remove, edit, publish }) {
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="授权"> <Tooltip title="授权">
<IconButton> <IconButton
onClick={() => {
authorized(product)
}}
>
<IconFont <IconFont
type="icon-shouquanguanli" type="icon-shouquanguanli"
style={{ fontSize: 20, color: "#ffffff" }} style={{ fontSize: 20, color: "#ffffff" }}
......
import { doFetch } from "@/utils/doFetch";
import {
ArrowDownOutlined,
ArrowRightOutlined,
FormOutlined,
MinusSquareOutlined,
PlusSquareOutlined,
} from "@ant-design/icons";
import EditIcon from "@mui/icons-material/Edit";
import { Box, colors, IconButton, Typography } from "@mui/material";
import { useRequest } from "ahooks";
import {
Divider,
Input,
message,
Modal,
Popconfirm,
Tooltip,
Tree,
} from "antd";
import { createContext, useEffect, useMemo, useState } from "react";
import "./index.less";
const ReachableContext = createContext(null);
let { Search } = Input,
{ TreeNode } = Tree;
const getParentKey = (key, tree) => {
let parentKey;
for (let i = 0; i < tree.length; i++) {
const node = tree[i];
if (node.children) {
if (
node.children.some((item) => {
return item.key === key;
})
) {
parentKey = node.key;
} else if (getParentKey(key, node.children)) {
parentKey = getParentKey(key, node.children);
}
}
}
return parentKey;
};
{
/* <TreeRender
url="/ngic-workmanship/pmMaterieType/queryTreeList"
deleteurl="/ngic-workmanship/pmMaterieType/deleteById"
saveurl="/ngic-workmanship/pmMaterieType/save"
onselected={(vals) => {
setmaterieTypeId(vals[0] ?? "");
}}
/> */
}
function TreeRender({
url,
deleteurl,
saveurl,
onselected,
params,
noaction,
maxWidth,
style,
submitKey,
courseId,
}) {
const [search, setsearch] = useState("");
const [savetitle, setsavetitle] = useState(null);
const [modal, setModal] = useState({
visible: false,
}),
[drawer, setDrawer] = useState({
item: null,
open: false,
});
const [expandall, setexpandall] = useState(false);
const [expandedKeys, onExpand] = useState();
const { data, loading, refresh } = useRequest(() => {
return doFetch({ url, params: params ?? {} });
});
console.log(data);
const [autoExpandParent, setAutoExpandParent] = useState(true);
const allkeys = useMemo(() => {
let res = [];
const fn = (source) => {
source?.map((el) => {
res.push(el);
el.children && el.children.length > 0 ? fn(el.children) : ""; // 子级递归
});
};
fn(data?.data?.data ?? []);
return res.filter((it) => it.children).map((it) => it.key);
}, [data]);
const alldata = useMemo(() => {
let res = [];
const fn = (source) => {
source?.map((el) => {
res.push(el);
el.children && el.children.length > 0 ? fn(el.children) : ""; // 子级递归
});
};
fn(data?.data?.data ?? []);
return res;
}, [data]);
const treeData = useMemo(() => {
let res = data?.data?.data ?? [];
return [
...res,
// {
// title: "查看实验",
// key: "cksy",
// },
// {
// title: "常见问题",
// key: "cjwt",
// },
];
}, [data]);
const onChange = (e) => {
const { value } = e.target;
const dataLists = getAllList();
const newExpandedKeys = dataLists
.map((item) => {
if (item.title.indexOf(value) > -1) {
return getParentKey(item.key, treeData);
}
return null;
})
.filter((item, i, self) => item && self.indexOf(item) === i);
setsearch(value);
if (newExpandedKeys.length > 0) {
setexpandall(true);
setAutoExpandParent(true);
} else {
setexpandall(false);
setAutoExpandParent(false);
}
onExpand(newExpandedKeys);
};
const loop = (data) =>
data.map((item) => {
const index = item.title.indexOf(search);
const beforeStr = item.title.substr(0, index);
const afterStr = item.title.substr(index + search.length);
let title =
index > -1 ? (
<Tooltip title={item.title} placement="topRight">
<span
style={{
display: "inline-block",
maxWidth: maxWidth ?? 88,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
marginRight: 6,
}}
>
{beforeStr}
<span style={{ color: "#f50" }}>{search}</span>
{afterStr}
</span>
</Tooltip>
) : (
<Tooltip title={item.title} placement="topRight">
<span
style={{
display: "inline-block",
maxWidth: maxWidth ?? 100,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
marginRight: 6,
}}
>
{item.title}
</span>
</Tooltip>
);
const actiontitle = (
<div
className="tree-item"
style={{
display: "flex",
alignItems: "start",
justifyContent: "space-between",
}}
>
<span style={{ marginRight: 6 }}>{title}</span>
<div className="tool-item">
{item.key && item.key != "00000000" && (
<Tooltip
title="编辑"
onClick={(e) => {
e.stopPropagation();
setsavetitle(null);
if (true) {
setModal({
visible: true,
closable: true,
title: "修改节点名称",
okText: "修改",
cancelText: "取消",
placeholder: item.title,
key: item.key,
});
}
}}
>
<FormOutlined style={{ color: "#1890ff" }} />
</Tooltip>
)}
{item.key && item.key != "00000000" && item.children && (
<Divider type="vertical" style={{ margin: "0 6px" }}></Divider>
)}
{item.key && item.key != "00000000" && item.children && (
<Tooltip title="新增">
<PlusSquareOutlined
disabled={false}
onClick={(e) => {
e.stopPropagation();
setsavetitle(null);
if (true) {
setModal({
visible: true,
closable: true,
title: "新增子结构",
okText: "新增",
cancelText: "取消",
placeholder: item.title,
key: item.key,
});
}
}}
style={{
color: `${true ? "green" : ""}`,
}}
/>
</Tooltip>
)}
{item.key != "0"&& (
<Divider type="vertical" style={{ margin: "0 6px" }}></Divider>
)}
{item.key != "0" && (
<Popconfirm
placement="top"
title="是否删除该节点?"
okText="删除"
cancelText="取消"
onConfirm={(e) => {
console.log(111);
doFetch({ url: deleteurl, params: { id: item.key } }).then(
(res) => {
if (res.code == "0000") {
message.success("操作成功");
refresh();
}
}
);
}}
>
<Tooltip title="删除">
<MinusSquareOutlined
onClick={(e) => {
e.stopPropagation();
}}
style={{ color: "red" }}
/>
</Tooltip>
</Popconfirm>
)}
{/* {
item.key === "00000000" && <Divider type='vertical' style={{ margin: "0 6px" }}></Divider>
} */}
{/* {
item.key === "00000000" && <Tooltip title={expandall ? "收起" : "展开"} onClick={(e) => {
e.stopPropagation();
setexpandall(!expandall)
onExpand(expandall ? [] : allkeys)
}}>
{expandall ? <ArrowDownOutlined /> : <ArrowRightOutlined />}
</Tooltip>
} */}
</div>
</div>
);
if (item.key === "00000000") {
title = (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
flex: 1,
}}
>
{title}
<Tooltip
title={expandall ? "收起" : "展开"}
onClick={(e) => {
e.stopPropagation();
setexpandall(!expandall);
onExpand(expandall ? [] : allkeys);
setAutoExpandParent(!expandall);
}}
>
{expandall ? <ArrowDownOutlined /> : <ArrowRightOutlined />}
</Tooltip>
</div>
);
}
if (item.children) {
return {
title: noaction ? title : actiontitle,
key: item.key,
children: loop(item.children),
level: item.level,
type: item.type,
};
}
return {
title: noaction ? title : actiontitle,
key: item.key,
level: item.level,
type: item.type,
icon: item.icon ?? null,
};
});
useEffect(() => {
setexpandall(true);
onExpand(allkeys);
}, [allkeys]);
function getAllList() {
const dataLists = [];
const generateLists = (data) => {
for (let i = 0; i < data.length; i++) {
const node = data[i];
const key = node.key;
dataLists.push({ key, title: node.title, level: node.level });
if (node.children) {
generateLists(node.children, node.key);
}
}
};
generateLists(treeData);
return dataLists;
}
return (
<>
<Box
flexDirection={"row"}
display={"flex"}
justifyContent={"space-between"}
alignItems={"center"}
mt={0}
>
<Typography variant="h6">课程目录</Typography>
<IconButton
onClick={() => {
setDrawer({ open: true });
}}
>
<EditIcon
style={{ fontSize: 20, color: colors.blue[100] }}
></EditIcon>
</IconButton>
<Modal
{...drawer}
closable={true}
title="新增章标题"
okText="新增"
cancelText="取消"
onCancel={() => {
setDrawer((s) => ({
item: null,
open: false,
}));
}}
onOk={() => {
return new Promise((resolve, reject) => {
if (drawer?.item) {
doFetch({
url: "/sysCourseTrain/saveOrUpdateCatalogue",
params: {
courseId,
catalogue: drawer.item,
},
}).then((res) => {
if (res.code == "0000") {
message.success("操作成功");
refresh();
setDrawer({
item: null,
open: false,
});
}
});
refresh();
resolve();
} else {
message.warning("请输入修改的名称");
reject();
}
});
}}
>
<div>
<Input
placeholder="请输入章标题"
allowClear
value={drawer?.item}
onChange={(e) => {
setDrawer((v) => ({
...v,
item: e.target.value,
}));
}}
></Input>
</div>
</Modal>
</Box>
<div style={{ ...style }}>
<Modal
{...modal}
onCancel={() => {
setModal((s) => ({
...s,
visible: false,
}));
}}
onOk={() => {
if (modal.okText == "修改") {
return new Promise((resolve, reject) => {
if (savetitle) {
doFetch({
url: saveurl,
params: {
[submitKey]: savetitle,
id: modal.key,
courseId,
},
}).then((res) => {
if (res.code == "0000") {
message.success("操作成功");
refresh();
setModal({
visible: false,
});
}
});
resolve();
} else {
message.warning("请输入修改的名称");
reject();
}
});
} else {
return new Promise((resolve, reject) => {
if (savetitle) {
doFetch({
url: saveurl,
params: {
[submitKey]: savetitle,
parentId: modal.key,
courseId,
},
}).then((res) => {
if (res.code == "0000") {
message.success("操作成功");
refresh();
setModal({
visible: false,
});
}
});
resolve();
} else {
message.warning("请输入修改的名称");
reject();
}
});
}
}}
>
{modal.okText == "修改" ? (
<div>
<Input
placeholder={modal.placeholder}
allowClear
value={savetitle}
onChange={(e) => {
setsavetitle(e.target.value);
}}
></Input>
</div>
) : (
<div>
<div style={{ marginBottom: 15, color: "#f50", fontSize: 16 }}>
当前结构:{modal.placeholder}
</div>
<Input
placeholder="子结构"
allowClear
onChange={(e) => {
setsavetitle(e.target.value);
}}
></Input>
</div>
)}
</Modal>
<Search
value={search}
style={{ margin: "16px 0 8px 0" }}
placeholder="搜索"
onChange={onChange}
/>
<Tree
showIcon
showLine
onSelect={(selectedKeys, e) => {
// //console.log(selectedKeys);
onselected?.(selectedKeys, e, alldata);
}}
autoExpandParent={autoExpandParent}
defaultExpandAll={true}
expandedKeys={expandedKeys}
onExpand={(expandedKeys, { expanded: bool, node }) => {
onExpand(expandedKeys);
setAutoExpandParent(false);
if (!bool && node.key == "00000000") {
setexpandall(false);
} else {
setexpandall(true);
}
}}
treeData={loop(treeData ?? [])}
>
{/* {loop(treeData ? treeData : [])} */}
</Tree>
</div>
</>
);
}
export default TreeRender;
html,
body,
#root {
height: 100%;
margin: 0 !important;
padding: 0 !important;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
pre {
margin: 0 !important;
}
.colorWeak {
filter: invert(80%);
}
.bf-content {
font-size: 14px !important;
}
.ant-layout {
min-height: 100vh;
}
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
left: unset;
}
canvas {
display: block;
}
body {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.oneline {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
ul,
ol {
list-style: none;
}
@media (max-width: 768px) {
.ant-table {
width: 100%;
overflow-x: auto;
}
.ant-table-thead > tr > th,
.ant-table-tbody > tr > th,
.ant-table-thead > tr > td,
.ant-table-tbody > tr > td {
white-space: pre;
}
.ant-table-thead > tr > th > span,
.ant-table-tbody > tr > th > span,
.ant-table-thead > tr > td > span,
.ant-table-tbody > tr > td > span {
display: block;
}
}
.bgtext {
letter-spacing: 0px !important;
text-transform: uppercase;
background-image: linear-gradient(145deg, #91daff 0%, #7bd1ff 25%, #ffa7ea 50%, #7bd1ff 75%, #91daff 100%);
background-clip: text;
animation: bgmove 20s linear 0s infinite alternate forwards;
-webkit-text-fill-color: transparent;
}
.center {
display: flex;
align-items: center;
justify-content: center;
}
.centerl {
display: flex;
align-items: center;
}
.spread {
display: flex;
align-items: center;
justify-content: space-between;
}
.columns {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
}
.bglight {
background-image: linear-gradient(145deg, #dbf3ff 0%, #c9ecff 25%, #ffdcf7 50%, #c9ecff 75%, #dbf3ff 100%);
background-size: 400% 400%;
animation: bgmove 20s linear 0s infinite alternate forwards;
}
@keyframes bgmove {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
form .ant-space {
display: flex;
align-items: center;
justify-content: flex-end;
}
.ant-popover-arrow {
display: none !important;
}
.ant-popconfirm-description {
font-size: 12px !important;
}
.ant-card-head {
padding: 0 8px !important;
border: none !important;
}
.hovercard .icon {
transform: scale(0);
transition: all 0.4s;
}
.hovercard:hover {
transform: scale(1);
}
.ant-card-actions {
background-color: rgba(255, 255, 255, 0) !important;
}
.ant-typography {
margin: 0 !important;
margin-right: 12px !important;
inset-inline-start: 0 !important;
}
.ant-typography .ant-input {
background-color: rgba(161, 161, 161, 0.553);
border: none;
outline: none;
box-shadow: none;
}
.ant-typography .ant-input:focus {
border: none;
outline: none;
box-shadow: none;
}
.bf-link-editor .buttons {
box-sizing: content-box !important;
}
.bf-container {
display: flex !important;
flex-direction: column !important;
}
.bf-container .bf-content {
flex: 1 !important;
}
.ant-segmented {
background-color: transparent !important;
}
.ant-segmented-item-selected div {
color: #0062be;
font-weight: bolder;
transition: all 0.4s;
}
.borderani {
box-shadow: 0 0 6px #0062be;
}
@keyframes lager {
from {
background-color: rgba(20, 119, 246, 0.8);
transform: scale(1);
}
to {
background-color: rgba(20, 119, 246, 0);
transform: scale(1.4);
}
}
.borderanis {
box-shadow: 0 0 6px #0062be;
}
.limit img {
max-width: 100% !important;
}
.limit video {
max-width: 100% !important;
}
.limit blockquote {
margin: 0 0 10px;
padding: 15px 20px;
color: #666;
font-style: italic;
background-color: #f1f2f3;
border-left: 5px solid #ccc;
}
.limit pre {
max-width: 100%;
max-height: 100%;
margin: 10px 0;
padding: 15px;
overflow: auto;
color: #666;
font-weight: 400;
font-size: 14px;
font-family: monospace;
line-height: 16px;
white-space: pre-wrap;
word-wrap: break-word;
background-color: #f1f2f3;
border-radius: 3px;
}
.limit * {
word-break: break-all !important;
}
.ant-pro-form-login-header {
height: auto !important;
}
.ant-pro-form-login-logo {
width: auto !important;
height: auto !important;
border-radius: 0 !important;
}
.ant-pro-form-login-logo img {
width: auto !important;
height: 100px !important;
border-radius: 0 !important;
}
.cards .ant-card-body {
padding: 8px !important;
padding-top: 0 !important;
}
.ant-card-extra {
display: flex;
gap: 6px;
}
.sorts {
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
background-color: rgba(0, 0, 0, 0.05);
border-radius: 6px;
cursor: pointer;
transition: all 0.4s;
}
.sorts:hover {
background-color: #dce6fc;
}
.sorts * {
transition: all 0.4s;
}
.ant-drawer-header {
flex: none !important;
height: 70px !important;
padding: 18px !important;
}
.ant-drawer-content {
background-color: #ffffff !important;
}
.ant-drawer-body {
padding: 0 !important;
}
*:focus {
outline: none !important;
}
.ant-segmented-item-label {
overflow: visible !important;
}
.badge {
display: flex;
align-items: center;
justify-content: center;
height: 18px;
margin-left: 6px;
padding: 0 6px;
color: #ffffff !important;
font-size: 12px !important;
background-color: #ff4800;
border-radius: 20px !important;
}
.info {
display: flex;
flex-direction: column;
align-items: center;
padding: 0 18px 0 12px;
}
.info b {
margin-top: 8px;
}
.hoveremoji {
width: 30px;
overflow: hidden;
transition: all 0.4s;
}
.hoveremoji:hover {
width: 298px;
}
.hoveremoji .emoji {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border-radius: 4px;
}
.hoveremoji .emoji:hover {
background-color: #ffffff !important;
}
.emojis {
display: flex;
gap: 3px;
align-items: center;
padding: 1px 6px 1px 4px;
border: 1px solid #ddd;
border-radius: 20px;
cursor: default;
cursor: pointer;
}
h4 {
margin: 0 !important;
}
.ant-list-item {
padding: 9px 18px !important;
}
.ant-list-item:hover {
background-color: #daebf4;
}
.ant-list-item-meta {
align-items: center !important;
}
.rightcontent {
position: fixed;
top: 136px;
right: 0;
height: calc(100vh - 150px);
margin: 0 !important;
overflow: hidden;
border-radius: 8px;
transition: all 0.4s;
}
.rightcontent .hovers {
position: absolute;
right: 0;
display: flex;
align-items: center;
justify-content: flex-start;
width: 0px;
height: 100%;
border-radius: 8px;
cursor: pointer;
transition: all 0.4s;
}
.rightcontent .hovers span {
opacity: 0;
transition: all 0.2s;
}
.rightcontent .hovers::after {
position: absolute;
top: 0;
right: 12px;
width: 0;
height: 100%;
background-color: transparent;
border: 1px solid transparent;
border-radius: 8px;
cursor: pointer;
transition: all 0.4s;
content: "";
}
.rightcontent:hover .hovers {
width: 50px;
}
.rightcontent:hover .hovers > span {
opacity: 0.8;
}
.rightcontent:hover .hovers::after {
position: absolute;
top: 0;
right: 12px;
width: 50px;
height: 100%;
border: 1px solid #f0f0f0;
border-radius: 8px;
box-shadow: 0 0 12px #dddddd;
cursor: pointer;
content: "";
}
.rightcontent .scrollcontian {
height: calc(100vh - 200px);
overflow: hidden;
}
.rightcontent .scrollcontian > div > div:last-child {
opacity: 0 !important;
}
.ant-list-item-action {
margin-inline-start: 12px !important;
}
.ant-drawer-extra {
display: flex !important;
gap: 8px !important;
}
.diycard {
margin-bottom: 6px;
padding: 4px 6px;
background-color: rgba(215, 240, 250, 0.499);
border-radius: 4px;
cursor: pointer !important;
}
.diycard > * {
font-size: 13px !important;
}
.react-resizable {
position: relative;
}
.table-cell {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.react-resizable-handle {
position: absolute;
right: -5px;
bottom: 0;
z-index: 999;
width: 10px;
height: 100%;
background: transparent;
cursor: col-resize;
}
.ant-pro-card {
border-radius: 12px !important;
}
.ant-pro-card-body {
padding-inline: 0 !important;
}
.ant-pro-table-list-toolbar-container {
padding-inline: 8px;
}
.ant-pro-table-list-toolbar-right {
flex: 1 !important;
flex-direction: row !important;
align-items: center !important;
justify-content: space-between !important;
}
.ant-pro-table-list-toolbar-left {
flex: 0;
}
.ant-table-pagination.ant-pagination {
padding-inline: 8px;
}
.ant-table-wrapper .ant-table-container table > thead > tr:first-child > *:last-child,
.ant-table-wrapper .ant-table-container table > thead > tr:first-child > *:first-child {
border-radius: 0 !important;
}
.ant-popover-arrow {
display: none !important;
}
.ant-upload {
overflow: hidden !important;
}
.MuiDrawer-paper {
z-index: 992 !important;
}
.MuiAppBar-root {
z-index: 990 !important;
}
.MuiDialog-root {
z-index: 999 !important;
}
.ant-tabs-nav {
margin-bottom: 0 !important;
}
.ant-tabs-nav::before {
border: none !important;
}
.ant-tabs-ink-bar-animated {
display: none !important;
}
.ant-tabs-tab-btn {
font-weight: bolder !important;
}
.ant-image-mask {
border-radius: 50%;
}
.hovered .actionhover {
position: absolute;
top: 6%;
display: flex;
align-items: flex-end;
width: 92%;
height: 92%;
}
.hovered .actionhover * {
transition: all 0.2s;
}
.hovered .actionhover .edit {
position: absolute;
top: 8px;
right: 8px;
transform: translateY(-80px);
}
.hovered .actionhover .masker {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.75);
opacity: 0;
}
.hovered .actionhover .stackani {
transform: translateY(80px);
margin-bottom: 8px;
}
.hovered:hover .actionhover {
position: absolute;
top: 6%;
display: flex;
align-items: flex-end;
width: 92%;
height: 92%;
}
.hovered:hover .actionhover .edit {
transform: translateY(0px);
}
.hovered:hover .actionhover .masker {
opacity: 1;
}
.hovered:hover .actionhover .stackani {
transform: translateY(0px);
}
.selecttable .ant-pro-table-list-toolbar-container {
margin-bottom: 24px!important;
}
.selecttable .ant-pagination-options > div {
width: auto!important;
}
...@@ -608,3 +608,15 @@ h4 { ...@@ -608,3 +608,15 @@ h4 {
} }
} }
} }
.selecttable {
.ant-pro-table-list-toolbar-container{
margin-bottom: 24px!important;
}
.ant-pagination-options {
>div{
width: auto!important;
}
}
}
\ No newline at end of file
import { Container } from '@mui/material'; import AutoTable from "@/components/AutoTable";
import React, { useState, useEffect } from 'react'; import DraggableDialog from "@/components/DraggableDialog";
import InitForm from "@/components/InitForm";
import PremButton from "@/components/PremButton";
import TreeRender from "@/components/TreeRender";
import { doFetch } from "@/utils/doFetch";
import editorIsNull from "@/utils/editorIsNull";
import { Box, Container, Grid, Link, Stack, Typography } from "@mui/material";
import { useParams } from "@umijs/max";
import { useRequest } from "ahooks";
import { message, Tabs } from "antd";
import { useEffect, useMemo, useRef, useState } from "react";
import { history } from "umi";
import "./index.less";
function Dolessons() { function Dolessons() {
const params = useParams();
const formRef = useRef(),
cksyactionRef = useRef(),
cjwtactionRef = useRef();
const [lessonDetail, setlessonDetail] = useState(null),
[courseContent, setCourseContent] = useState({}),
[drawer, setDrawer] = useState({
open: false,
}),
[active, setactive] = useState("1");
const { runAsync, loading } = useRequest(doFetch, {
manual: true,
onSuccess: (res, parames) => {
if (res?.code == "0000") {
handleClose();
message.success("操作成功");
if (active === "2") {
cksyactionRef?.current?.reload();
} else if (active === "3") {
cjwtactionRef?.current?.reload();
}
}
},
});
useEffect(() => {
doFetch({ url: "/sysCourse/detail", params: { id: params?.id } }).then(
(res) => {
if (res.code === "0000") {
setlessonDetail(res?.data?.data);
}
}
);
}, []);
const checkCourse = (val) => {
if (val.length) {
doFetch({
url: "/sysCourseTrain/getCourseTrain",
params: { id: val[0] },
}).then((res) => {
setCourseContent(res?.data?.data);
formRef.current.setFieldValue(
"trainContent",
res?.data?.data?.trainContent
);
});
}
};
useEffect(() => {
if (courseContent?.id) {
alert(0)
}
}, [courseContent?.id]);
const edit = (text, row, _, action) => {
return (
<PremButton
btn={{
size: "small",
variant: "text",
onClick: () => {
setDrawer((v) => ({
open: true,
defaultFormValue: { ...row },
title: "编辑",
}));
},
}}
>
编辑
</PremButton>
);
};
const remove = (text, row, _, action) => {
return (
<PremButton
pop={{
title: "是否删除该实验?",
okText: "确认",
cancelText: "取消",
onConfirm: async () => {
await runAsync({
url: "/courseExperiment/delete",
params: { id: row?.id },
});
},
}}
btn={{
size: "small",
color: "error",
}}
>
删除
</PremButton>
);
};
const removeq = (text, row, _, action) => {
return (
<PremButton
pop={{
title: "是否删除该实验?",
okText: "确认",
cancelText: "取消",
onConfirm: async () => {
await runAsync({
url: "/courseQuestion/delete",
params: { id: row?.id },
});
},
}}
btn={{
size: "small",
color: "error",
}}
>
删除
</PremButton>
);
};
const questionColumns = useMemo(() => {
let col = [
{
title: "问题内容",
dataIndex: "question",
key: "question",
width:400,
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
},
{
title: "参考答案",
dataIndex: "answer",
key: "answer",
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
},
];
return col;
}, []);
const experimentColumns = useMemo(() => {
let col = [
{
title: "实验名称",
dataIndex: "experimentName",
key: "experimentName",
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
render: (_, row) => {
return (
<Link
underline="hover"
href={row?.url}
target="_blank"
rel="noopener"
>
{row?.experimentName}
</Link>
);
},
search: false,
},
{
title: "模型ID",
dataIndex: "modelId",
search: false,
key: "modelId",
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
},
{
title: "模型名称",
dataIndex: "modelName",
search: false,
key: "modelName",
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
},
{
title: "考试时间(分钟)",
search: false,
dataIndex: "testTime",
key: "testTime",
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
},
{
title: "权重(%)",
search: false,
dataIndex: "weight",
key: "weight",
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
},
{
search: false,
title: "创建人",
dataIndex: "createUserName",
key: "createUserName",
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
},
{
title: "创建时间",
dataIndex: "createTime",
search: false,
key: "createTime",
formItemProps: { rules: [{ required: true, message: "此项为必填项" }] },
},
];
return col;
}, []);
const items = [
{
key: "1",
label: `课程目录`,
children: (
<Grid container spacing={2}>
<Grid item xs={3}>
<Box boxShadow={"0 0 18px #f0f0f0"} borderRadius={2} padding={2}>
<TreeRender
onselected={checkCourse}
maxWidth={170}
courseId={params?.id}
url="/sysCourseTrain/queryCatalogueTree"
saveurl="/sysCourseTrain/saveOrUpdateCatalogue"
deleteurl="/sysCourseTrain/deleteCatalogue"
submitKey="catalogue"
params={{
courseId: params?.id,
}}
/>
</Box>
</Grid>
<Grid item xs={9}>
<Box boxShadow={"0 0 18px #f0f0f0"} borderRadius={2} padding={2}>
<InitForm
formRef={formRef}
fields={[
{
key: "trainContent",
dataIndex: "trainContent",
valueType: "Editor",
colProps: {
span: 24,
},
},
]}
onFinish={(val) => {
const data = { ...val };
if (editorIsNull(data?.trainContent)) {
return message.warning("备课内容不能为空!", 2);
}
doFetch({
url: "/sysCourseTrain/saveOrUpdateCourseTrain",
params: {
id: courseContent?.id,
trainContent: data?.trainContent,
},
}).then((res) => {
if (res.code === "0000") {
message.success("操作成功!");
}
});
}}
/>
</Box>
</Grid>
</Grid>
),
},
{
key: "2",
label: "查看实验",
children: (
<Box boxShadow={"0 0 18px #f0f0f0"} borderRadius={2}>
<AutoTable
rerendered={false}
actionRef={cksyactionRef}
columns={[
...experimentColumns,
{
title: "操作",
valueType: "option",
width: 180,
render: (text, row, _, action) => [
edit(text, row, _, action),
remove(text, row, _, action),
],
},
]}
path="/courseExperiment/page"
extraparams={{
courseId: params?.id,
}}
/>
</Box>
),
},
{
key: "3",
label: "常见问题",
children: (
<Box boxShadow={"0 0 18px #f0f0f0"} borderRadius={2}>
<AutoTable
rerendered={false}
actionRef={cjwtactionRef}
columns={[
...questionColumns,
{
title: "操作",
valueType: "option",
width: 180,
render: (text, row, _, action) => [
edit(text, row, _, action),
removeq(text, row, _, action),
],
},
]}
path="/courseQuestion/page"
extraparams={{
courseId: params?.id,
}}
/>
</Box>
),
},
];
const addHandel = (val) => {
if (active === "1") {
// 预览
} else if (active === "2") {
// 添加实验
setDrawer({ open: true, title: "添加实验" });
} else {
// 添加问题
setDrawer({ open: true, title: "添加问题" });
}
};
const handleClose = () => {
setDrawer((s) => ({
...s,
open: false,
}));
};
return ( return (
<Container maxWidth={false}> <Container maxWidth={false}>
123 <DraggableDialog
handleClose={handleClose}
dialogprops={drawer}
loading={loading}
maxWidth={drawer?.maxWidth ?? "sm"}
>
{active === "2" ? (
<InitForm
defaultFormValue={drawer?.defaultFormValue ?? null}
fields={[
{
title: "实验名称",
dataIndex: "experimentName",
key: "experimentName",
},
{
title: "仿真模型(单选)",
dataIndex: "modelId",
key: "modelId",
valueType: "select",
options: {
path: "/model/selection",
},
},
{
title: "考试时间(分钟)",
dataIndex: "testTime",
key: "testTime",
valueType: "digit",
},
{
title: "权重",
dataIndex: "weight",
key: "weight",
valueType: "digit",
},
]}
onFinish={(val, extra) => {
let postdata;
switch (drawer?.title) {
case "添加实验":
postdata = {
...val,
courseId: params?.id,
};
break;
case "编辑":
postdata = {
...val,
id: drawer?.defaultFormValue?.id,
courseId: params?.id,
};
default:
break;
}
runAsync({
url: "/courseExperiment/saveOrUpdate",
params: postdata,
});
}}
></InitForm>
) : (
<InitForm
defaultFormValue={drawer?.defaultFormValue ?? null}
fields={[
{
title: "问题内容",
dataIndex: "question",
key: "question",
valueType: "textarea",
},
{
title: "参考答案",
dataIndex: "answer",
key: "answer",
valueType: "textarea",
},
]}
onFinish={(val, extra) => {
let postdata;
switch (drawer?.title) {
case "添加问题":
postdata = {
...val,
courseId: params?.id,
};
break;
case "编辑":
postdata = {
...val,
id: drawer?.defaultFormValue?.id,
courseId: params?.id,
};
default:
break;
}
runAsync({
url: "/courseQuestion/saveOrUpdate",
params: postdata,
});
}}
></InitForm>
)}
</DraggableDialog>
<Box
display={"flex"}
justifyContent={"space-between"}
alignItems={"center"}
sx={{ mb: 2.5 }}
mt={0}
>
<Typography variant="h5">
{lessonDetail?.courseName ?? "暂无名称"}
</Typography>
<Stack spacing={2} direction="row">
<PremButton
btn={{
variant: "outlined",
onClick: (e) => {
e.stopPropagation();
history.back();
},
}}
>
返回
</PremButton>
<PremButton
btn={{
variant: "contained",
onClick: addHandel,
}}
>
{active === "1" ? "预览" : active === "2" ? "添加实验" : "添加问题"}
</PremButton>
</Stack>
</Box>
<Box>
<Tabs
activeKey={active}
onChange={setactive}
items={items}
tabPosition="top"
animated={true}
/>
</Box>
</Container> </Container>
); );
} }
......
...@@ -9,11 +9,10 @@ import PRODUCTS from "@/_mock/products"; ...@@ -9,11 +9,10 @@ import PRODUCTS from "@/_mock/products";
import { Box, Container, Grid, Stack, Typography } from "@mui/material"; import { Box, Container, Grid, Stack, Typography } from "@mui/material";
import { useRequest } from "ahooks"; import { useRequest } from "ahooks";
import { Empty, message } from "antd"; import { Empty, message } from "antd";
import { useMemo, useRef, useState } from "react"; import { useMemo, useState } from "react";
import "./index.less"; import "./index.less";
function Lessons() { function Lessons() {
const actionRef = useRef();
const [dialogprops, setdialogprops] = useState({ const [dialogprops, setdialogprops] = useState({
open: false, open: false,
}); });
...@@ -59,6 +58,24 @@ function Lessons() { ...@@ -59,6 +58,24 @@ function Lessons() {
}); });
}; };
const authorized = (row) => {
doFetch({
url: "/sysCourseTeacher/queryRelationTeacher",
params: { courseId: row?.id },
}).then((res) => {
if (res.code === "0000") {
console.log(res?.data?.dataList);
setdialogprops({
open: true,
maxWidth: "xl",
defaultFormValue: { ...row },
teacherIdList: res?.data?.dataList,
title: "授权",
});
}
});
};
const remove = (row) => { const remove = (row) => {
runAsync({ runAsync({
url: "/sysCourse/delete", url: "/sysCourse/delete",
...@@ -109,6 +126,7 @@ function Lessons() { ...@@ -109,6 +126,7 @@ function Lessons() {
dialogprops={dialogprops} dialogprops={dialogprops}
maxWidth={dialogprops?.maxWidth ?? "xs"} maxWidth={dialogprops?.maxWidth ?? "xs"}
> >
{dialogprops?.title === "编辑" ? (
<InitForm <InitForm
fields={columns} fields={columns}
defaultFormValue={dialogprops?.defaultFormValue} defaultFormValue={dialogprops?.defaultFormValue}
...@@ -130,8 +148,66 @@ function Lessons() { ...@@ -130,8 +148,66 @@ function Lessons() {
}); });
}} }}
></InitForm> ></InitForm>
) : (
<InitForm
// defaultFormValue={{
// teacherIdList: dialogprops?.teacherIdList,
// }}
fields={[
{
rowKey: "id",
rowName: "id",
valueType: "FormSelectList",
dataIndex: "teacherIdList",
colProps: {
span: 24,
},
columns: [
{
title: "账号",
key: "userAccount",
dataIndex: "userAccount",
readonly: true,
},
{
title: "教师姓名",
key: "name",
dataIndex: "name",
readonly: true,
},
{
title: "学校名称",
key: "schoolName",
dataIndex: "schoolName",
readonly: true,
},
{
title: "院系名称",
key: "departmentName",
dataIndex: "departmentName",
readonly: true,
},
],
path: "/user/page",
params: {
type: "2",
},
},
]}
onFinish={(val) => {
console.log(val);
const teacherIdList = val?.teacherIdList?.map((it) => it?.id);
runAsync({
url: "/sysCourseTeacher/relationCourseTeacher",
params: {
teacherIdList,
courseId: dialogprops?.defaultFormValue?.id,
},
});
}}
/>
)}
</DraggableDialog> </DraggableDialog>
<Box <Box
display={"flex"} display={"flex"}
justifyContent={"space-between"} justifyContent={"space-between"}
...@@ -183,6 +259,7 @@ function Lessons() { ...@@ -183,6 +259,7 @@ function Lessons() {
edit={edit} edit={edit}
remove={remove} remove={remove}
publish={publish} publish={publish}
authorized={authorized}
/> />
</Grid> </Grid>
)) ))
......
// 传入富文本内容 string , 判断当前富文本是否有输入内容
export default (content) => {
let filterContent = content.replace(/<[^<>]+>/g, "").replace(/&nbsp;/gi, "");
if (filterContent == "") return true;
let regu = "^[ ]+$";
let re = new RegExp(regu);
return re.test(filterContent);
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment