@@ -1 +0,0 @@ | |||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg> |
@@ -0,0 +1,38 @@ | |||||
.filter { | |||||
box-sizing: border-box; | |||||
min-width: 220px; | |||||
height: 100%; | |||||
padding: 18px; | |||||
margin-right: 10px; | |||||
.title { | |||||
margin: 0 0 15px; | |||||
font-size: 18px; | |||||
font-weight: bold; | |||||
color: var(--el-text-color-regular); | |||||
letter-spacing: 0.5px; | |||||
} | |||||
.el-input { | |||||
margin: 0 0 15px; | |||||
} | |||||
.el-scrollbar { | |||||
:deep(.el-tree) { | |||||
height: 80%; | |||||
overflow: auto; | |||||
.el-tree-node__content { | |||||
height: 33px; | |||||
} | |||||
} | |||||
:deep(.el-tree--highlight-current) { | |||||
.el-tree-node.is-current > .el-tree-node__content { | |||||
background-color: var(--el-color-primary); | |||||
.el-tree-node__label, | |||||
.el-tree-node__expand-icon { | |||||
color: white; | |||||
} | |||||
.is-leaf { | |||||
color: transparent; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,201 @@ | |||||
<template> | |||||
<div class="card filter"> | |||||
<h4 v-if="title" class="title sle"> | |||||
{{ title }} | |||||
</h4> | |||||
<el-input v-model="filterText" placeholder="输入关键字进行过滤" clearable /> | |||||
<el-scrollbar :style="{ height: title ? `calc(100% - 95px)` : `calc(100% - 56px)` }"> | |||||
<el-tree | |||||
ref="treeRef" | |||||
default-expand-all | |||||
:node-key="id" | |||||
:data="multiple ? treeData : treeAllData" | |||||
:show-checkbox="multiple" | |||||
:check-strictly="false" | |||||
:current-node-key="!multiple ? selected : ''" | |||||
:highlight-current="!multiple" | |||||
:expand-on-click-node="false" | |||||
:check-on-click-node="multiple" | |||||
:props="defaultProps" | |||||
:filter-node-method="filterNode" | |||||
:default-checked-keys="multiple ? selected : []" | |||||
@node-click="handleNodeClick" | |||||
@check="handleCheckChange" | |||||
> | |||||
<!-- <template #default="scope"> | |||||
<span class="el-tree-node__label"> | |||||
<slot :row="scope"> | |||||
{{ scope.node.label }} | |||||
</slot> | |||||
</span> | |||||
</template> --> | |||||
<template #default="{ node, data }"> | |||||
<span class="custom-tree-node"> | |||||
{{ node.label }} | |||||
<!-- <template v-else> | |||||
<el-input v-model="editingNodeLabel" @blur="cancelEdit" @keyup.enter="updateNodeLabel(data)"></el-input> | |||||
</template> --> | |||||
<span v-if="operate"> | |||||
<a :style="{ marginRight: '0.5rem' }" @click.stop="edit(node, data)"> | |||||
<el-icon :style="{ color: '#0000FF' }"> | |||||
<Edit /> | |||||
</el-icon> | |||||
</a> | |||||
<a :style="{ marginRight: '0.5rem' }" @click.stop="remove(node, data)"> | |||||
<el-icon :style="{ color: '#DA3434' }"> | |||||
<Delete /> | |||||
</el-icon> | |||||
</a> | |||||
</span> | |||||
</span> | |||||
</template> | |||||
<!-- <span slot-scope="{ node, data }"> | |||||
<span class="el-tree-node__label"> | |||||
{{ node.label }} | |||||
</span> | |||||
</span> --> | |||||
</el-tree> | |||||
</el-scrollbar> | |||||
<ClassifyDialog ref="dialogRef"></ClassifyDialog> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts" name="BookListFilter"> | |||||
import { ref, watch, onBeforeMount, nextTick } from "vue"; | |||||
import { ElTree } from "element-plus"; | |||||
import ClassifyDialog from "@/views/books/bookListManage/components/ClassifyDialog.vue"; | |||||
// 接收父组件参数并设置默认值 | |||||
interface TreeFilterProps { | |||||
requestApi?: (data?: any) => Promise<any>; // 请求分类数据的 api ==> 非必传 | |||||
data?: { [key: string]: any }[]; // 分类数据,如果有分类数据,则不会执行 api 请求 ==> 非必传 | |||||
title?: string; // treeFilter 标题 ==> 非必传 | |||||
id?: string; // 选择的id ==> 非必传,默认为 “id” | |||||
label?: string; // 显示的label ==> 非必传,默认为 “label” | |||||
multiple?: boolean; // 是否为多选 ==> 非必传,默认为 false | |||||
defaultValue?: any; // 默认选中的值 ==> 非必传 | |||||
operate?: boolean; // 是否展示编辑删除 默认false | |||||
} | |||||
const props = withDefaults(defineProps<TreeFilterProps>(), { | |||||
id: "id", | |||||
label: "label", | |||||
multiple: false, | |||||
operate: false | |||||
}); | |||||
const defaultProps = { | |||||
children: "children", | |||||
label: props.label | |||||
}; | |||||
/** 树形结构数据 */ | |||||
interface Tree { | |||||
[key: string]: any; | |||||
} | |||||
const treeRef = ref<InstanceType<typeof ElTree>>(); | |||||
const treeData = ref<{ [key: string]: any }[]>([]); | |||||
const treeAllData = ref<{ [key: string]: any }[]>([]); | |||||
const selected = ref(); | |||||
const setSelected = () => { | |||||
if (props.multiple) selected.value = Array.isArray(props.defaultValue) ? props.defaultValue : [props.defaultValue]; | |||||
else selected.value = typeof props.defaultValue === "string" ? props.defaultValue : ""; | |||||
}; | |||||
const dialogRef = ref<InstanceType<typeof ClassifyDialog> | null>(null); | |||||
const edit = (node: Node, data: Tree) => { | |||||
console.log("node", node); | |||||
console.log("data", data); | |||||
console.log("打开弹窗"); | |||||
dialogRef.value?.open().then(); | |||||
// const newChild = { id: id++, label: "testtest", children: [] }; | |||||
// if (!data.children) { | |||||
// data.children = []; | |||||
// } | |||||
// data.children.push(newChild); | |||||
// dataSource.value = [...dataSource.value]; | |||||
}; | |||||
/** 删除树节点 */ | |||||
const remove = (node: Node, data: Tree) => { | |||||
console.log("node", node); | |||||
console.log("data", data); | |||||
const parent = node?.parent; | |||||
const children: Tree[] = parent.data.children || parent.data; | |||||
const index = children.findIndex(d => d.id === data.id); | |||||
children.splice(index, 1); | |||||
const dataResult = props.multiple ? treeData : treeAllData; | |||||
dataResult.value = [...dataResult.value]; | |||||
}; | |||||
onBeforeMount(async () => { | |||||
setSelected(); | |||||
if (props.requestApi) { | |||||
const { data } = await props.requestApi!(); | |||||
treeData.value = data; | |||||
treeAllData.value = [...data]; | |||||
// treeAllData.value = [{ id: "", [props.label]: "全部" }, ...data]; | |||||
} | |||||
}); | |||||
// 使用 nextTick 防止打包后赋值不生效,开发环境是正常的 | |||||
watch( | |||||
() => props.defaultValue, | |||||
() => nextTick(() => setSelected()), | |||||
{ deep: true, immediate: true } | |||||
); | |||||
watch( | |||||
() => props.data, | |||||
() => { | |||||
if (props.data?.length) { | |||||
treeData.value = props.data; | |||||
treeAllData.value = [...props.data]; | |||||
// treeAllData.value = [{ id: "", [props.label]: "全部" }, ...props.data]; | |||||
} | |||||
}, | |||||
{ deep: true, immediate: true } | |||||
); | |||||
const filterText = ref(""); | |||||
watch(filterText, val => { | |||||
treeRef.value!.filter(val); | |||||
}); | |||||
// 过滤 | |||||
const filterNode = (value: string, data: { [key: string]: any }, node: any) => { | |||||
if (!value) return true; | |||||
let parentNode = node.parent, | |||||
labels = [node.label], | |||||
level = 1; | |||||
while (level < node.level) { | |||||
labels = [...labels, parentNode.label]; | |||||
parentNode = parentNode.parent; | |||||
level++; | |||||
} | |||||
return labels.some(label => label.indexOf(value) !== -1); | |||||
}; | |||||
// emit | |||||
const emit = defineEmits<{ | |||||
change: [value: any]; | |||||
}>(); | |||||
// 单选 | |||||
const handleNodeClick = (data: { [key: string]: any }) => { | |||||
if (props.multiple) return; | |||||
emit("change", data[props.id]); | |||||
}; | |||||
// 多选 | |||||
const handleCheckChange = () => { | |||||
emit("change", treeRef.value?.getCheckedKeys()); | |||||
}; | |||||
// 暴露给父组件使用 | |||||
defineExpose({ treeData, treeAllData, treeRef }); | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
@import "./index.scss"; | |||||
</style> |
@@ -22,48 +22,21 @@ | |||||
@node-click="handleNodeClick" | @node-click="handleNodeClick" | ||||
@check="handleCheckChange" | @check="handleCheckChange" | ||||
> | > | ||||
<!-- <template #default="scope"> | |||||
<template #default="scope"> | |||||
<span class="el-tree-node__label"> | <span class="el-tree-node__label"> | ||||
<slot :row="scope"> | <slot :row="scope"> | ||||
{{ scope.node.label }} | {{ scope.node.label }} | ||||
</slot> | </slot> | ||||
</span> | </span> | ||||
</template> --> | |||||
<template #default="{ node, data }"> | |||||
<span class="custom-tree-node"> | |||||
{{ node.label }} | |||||
<!-- <template v-else> | |||||
<el-input v-model="editingNodeLabel" @blur="cancelEdit" @keyup.enter="updateNodeLabel(data)"></el-input> | |||||
</template> --> | |||||
<span v-if="operate"> | |||||
<a :style="{ marginRight: '0.5rem' }" @click.stop="edit(node, data)"> | |||||
<el-icon :style="{ color: '#0000FF' }"> | |||||
<Edit /> | |||||
</el-icon> | |||||
</a> | |||||
<a :style="{ marginRight: '0.5rem' }" @click.stop="remove(node, data)"> | |||||
<el-icon :style="{ color: '#DA3434' }"> | |||||
<Delete /> | |||||
</el-icon> | |||||
</a> | |||||
</span> | |||||
</span> | |||||
</template> | </template> | ||||
<!-- <span slot-scope="{ node, data }"> | |||||
<span class="el-tree-node__label"> | |||||
{{ node.label }} | |||||
</span> | |||||
</span> --> | |||||
</el-tree> | </el-tree> | ||||
</el-scrollbar> | </el-scrollbar> | ||||
<ClassifyDialog ref="dialogRef"></ClassifyDialog> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="ts" name="TreeFilter"> | <script setup lang="ts" name="TreeFilter"> | ||||
import { ref, watch, onBeforeMount, nextTick } from "vue"; | import { ref, watch, onBeforeMount, nextTick } from "vue"; | ||||
import { ElTree } from "element-plus"; | import { ElTree } from "element-plus"; | ||||
import ClassifyDialog from "@/views/books/bookListManage/components/ClassifyDialog.vue"; | |||||
// 接收父组件参数并设置默认值 | // 接收父组件参数并设置默认值 | ||||
interface TreeFilterProps { | interface TreeFilterProps { | ||||
@@ -74,13 +47,11 @@ interface TreeFilterProps { | |||||
label?: string; // 显示的label ==> 非必传,默认为 “label” | label?: string; // 显示的label ==> 非必传,默认为 “label” | ||||
multiple?: boolean; // 是否为多选 ==> 非必传,默认为 false | multiple?: boolean; // 是否为多选 ==> 非必传,默认为 false | ||||
defaultValue?: any; // 默认选中的值 ==> 非必传 | defaultValue?: any; // 默认选中的值 ==> 非必传 | ||||
operate?: boolean; // 是否展示编辑删除 默认false | |||||
} | } | ||||
const props = withDefaults(defineProps<TreeFilterProps>(), { | const props = withDefaults(defineProps<TreeFilterProps>(), { | ||||
id: "id", | id: "id", | ||||
label: "label", | label: "label", | ||||
multiple: false, | |||||
operate: false | |||||
multiple: false | |||||
}); | }); | ||||
const defaultProps = { | const defaultProps = { | ||||
@@ -88,11 +59,6 @@ const defaultProps = { | |||||
label: props.label | label: props.label | ||||
}; | }; | ||||
/** 树形结构数据 */ | |||||
interface Tree { | |||||
[key: string]: any; | |||||
} | |||||
const treeRef = ref<InstanceType<typeof ElTree>>(); | const treeRef = ref<InstanceType<typeof ElTree>>(); | ||||
const treeData = ref<{ [key: string]: any }[]>([]); | const treeData = ref<{ [key: string]: any }[]>([]); | ||||
const treeAllData = ref<{ [key: string]: any }[]>([]); | const treeAllData = ref<{ [key: string]: any }[]>([]); | ||||
@@ -102,39 +68,13 @@ const setSelected = () => { | |||||
if (props.multiple) selected.value = Array.isArray(props.defaultValue) ? props.defaultValue : [props.defaultValue]; | if (props.multiple) selected.value = Array.isArray(props.defaultValue) ? props.defaultValue : [props.defaultValue]; | ||||
else selected.value = typeof props.defaultValue === "string" ? props.defaultValue : ""; | else selected.value = typeof props.defaultValue === "string" ? props.defaultValue : ""; | ||||
}; | }; | ||||
const dialogRef = ref<InstanceType<typeof ClassifyDialog> | null>(null); | |||||
const edit = (node: Node, data: Tree) => { | |||||
console.log("node", node); | |||||
console.log("data", data); | |||||
console.log("打开弹窗"); | |||||
dialogRef.value?.open().then(); | |||||
// const newChild = { id: id++, label: "testtest", children: [] }; | |||||
// if (!data.children) { | |||||
// data.children = []; | |||||
// } | |||||
// data.children.push(newChild); | |||||
// dataSource.value = [...dataSource.value]; | |||||
}; | |||||
/** 删除树节点 */ | |||||
const remove = (node: Node, data: Tree) => { | |||||
console.log("node", node); | |||||
console.log("data", data); | |||||
const parent = node?.parent; | |||||
const children: Tree[] = parent.data.children || parent.data; | |||||
const index = children.findIndex(d => d.id === data.id); | |||||
children.splice(index, 1); | |||||
const dataResult = props.multiple ? treeData : treeAllData; | |||||
dataResult.value = [...dataResult.value]; | |||||
}; | |||||
onBeforeMount(async () => { | onBeforeMount(async () => { | ||||
setSelected(); | setSelected(); | ||||
if (props.requestApi) { | if (props.requestApi) { | ||||
const { data } = await props.requestApi!(); | const { data } = await props.requestApi!(); | ||||
treeData.value = data; | treeData.value = data; | ||||
treeAllData.value = [...data]; | |||||
// treeAllData.value = [{ id: "", [props.label]: "全部" }, ...data]; | |||||
treeAllData.value = [{ id: "", [props.label]: "全部" }, ...data]; | |||||
} | } | ||||
}); | }); | ||||
@@ -150,8 +90,7 @@ watch( | |||||
() => { | () => { | ||||
if (props.data?.length) { | if (props.data?.length) { | ||||
treeData.value = props.data; | treeData.value = props.data; | ||||
treeAllData.value = [...props.data]; | |||||
// treeAllData.value = [{ id: "", [props.label]: "全部" }, ...props.data]; | |||||
treeAllData.value = [{ id: "", [props.label]: "全部" }, ...props.data]; | |||||
} | } | ||||
}, | }, | ||||
{ deep: true, immediate: true } | { deep: true, immediate: true } | ||||
@@ -7,7 +7,7 @@ export const HOME_URL: string = "/"; | |||||
export const LOGIN_URL: string = "/login"; | export const LOGIN_URL: string = "/login"; | ||||
// 默认主题颜色 | // 默认主题颜色 | ||||
export const DEFAULT_PRIMARY: string = "#BA7D45"; // #0C655D | |||||
export const DEFAULT_PRIMARY: string = "#0C655D"; // #BA7D45 | |||||
// 路由白名单地址(本地存在的路由 staticRouter.ts 中) | // 路由白名单地址(本地存在的路由 staticRouter.ts 中) | ||||
export const ROUTER_WHITE_LIST: string[] = ["/500"]; | export const ROUTER_WHITE_LIST: string[] = ["/500"]; | ||||
@@ -3,7 +3,7 @@ import { Theme } from "@/hooks/interface"; | |||||
export const menuTheme: Record<Theme.ThemeType, { [key: string]: string }> = { | export const menuTheme: Record<Theme.ThemeType, { [key: string]: string }> = { | ||||
light: { | light: { | ||||
"--el-bg-color-page": "#F8F7F5", | "--el-bg-color-page": "#F8F7F5", | ||||
"--el-menu-bg-color": "#ECD8BE", | |||||
"--el-menu-bg-color": "#fffff", | |||||
"--el-menu-hover-bg-color": "rgba(255, 255, 255, .7)", | "--el-menu-hover-bg-color": "rgba(255, 255, 255, .7)", | ||||
"--el-menu-active-bg-color": "#FFFFFF", | "--el-menu-active-bg-color": "#FFFFFF", | ||||
"--el-menu-text-color": "#340D00", | "--el-menu-text-color": "#340D00", | ||||
@@ -1,206 +0,0 @@ | |||||
<!-- 新增/编辑书目 --> | |||||
<template> | |||||
<el-dialog | |||||
v-model="dialogVisible" | |||||
:title="isAdd ? '添加' : '编辑'" | |||||
:width="500" | |||||
center | |||||
align-center | |||||
:close-on-click-modal="false" | |||||
@closed="handleBeforeClose" | |||||
> | |||||
<el-form :model="formData" ref="formRef" label-width="150px" :rules="formRules" class="mt20"> | |||||
<el-form-item label="所属分类" prop="knowledgeCellName"> | |||||
<el-tree-select v-model="formData.knowledgeCellName" :data="data" filterable /> | |||||
</el-form-item> | |||||
<el-form-item label="书名名称" prop="isKnowledgeName" maxlength="50"> | |||||
<el-input v-model="formData.annotation" placeholder="请输入分类名称" :maxlength="50" /> | |||||
</el-form-item> | |||||
<el-form-item label="作者" prop="author"> | |||||
<el-input v-model="formData.author" placeholder="请输入作者" :maxlength="50" /> | |||||
</el-form-item> | |||||
<el-form-item label="出版时间" prop="time"> | |||||
<el-input v-model="formData.time" placeholder="请输入出版时间" :maxlength="50" /> | |||||
</el-form-item> | |||||
<el-form-item label="提要" prop="annotation"> | |||||
<el-input v-model="formData.annotation" placeholder="请输入提要" :maxlength="1000" /> | |||||
</el-form-item> | |||||
</el-form> | |||||
<template #footer> | |||||
<span class="dialog-footer"> | |||||
<el-button @click="handleCancel">取消</el-button> | |||||
<el-button type="primary" class="ml30" v-throttle="handleSubmit">确定</el-button> | |||||
</span> | |||||
</template> | |||||
</el-dialog> | |||||
</template> | |||||
<script lang="ts" setup name="editBookList"> | |||||
import { ref, reactive, nextTick } from "vue"; | |||||
import { FormInstance, FormRules, ElMessage } from "element-plus"; | |||||
//* 接收注入 | |||||
const dialogVisible = ref(false); | |||||
//* data | |||||
//* ref | |||||
const formRef = ref<FormInstance>(); | |||||
const openPromise = ref<any>({}); | |||||
const isAdd = ref(false); | |||||
const formData = reactive<FormData>(getFormDefaultValue()); | |||||
const sourceData = [ | |||||
{ | |||||
value: "1", | |||||
label: "Level one 1", | |||||
children: [ | |||||
{ | |||||
value: "1-1", | |||||
label: "Level two 1-1", | |||||
children: [ | |||||
{ | |||||
value: "1-1-1", | |||||
label: "Level three 1-1-1" | |||||
} | |||||
] | |||||
} | |||||
] | |||||
}, | |||||
{ | |||||
value: "2", | |||||
label: "Level one 2", | |||||
children: [ | |||||
{ | |||||
value: "2-1", | |||||
label: "Level two 2-1", | |||||
children: [ | |||||
{ | |||||
value: "2-1-1", | |||||
label: "Level three 2-1-1" | |||||
} | |||||
] | |||||
}, | |||||
{ | |||||
value: "2-2", | |||||
label: "Level two 2-2", | |||||
children: [ | |||||
{ | |||||
value: "2-2-1", | |||||
label: "Level three 2-2-1" | |||||
} | |||||
] | |||||
} | |||||
] | |||||
}, | |||||
{ | |||||
value: "3", | |||||
label: "Level one 3", | |||||
children: [ | |||||
{ | |||||
value: "3-1", | |||||
label: "Level two 3-1", | |||||
children: [ | |||||
{ | |||||
value: "3-1-1", | |||||
label: "Level three 3-1-1" | |||||
} | |||||
] | |||||
}, | |||||
{ | |||||
value: "3-2", | |||||
label: "Level two 3-2", | |||||
children: [ | |||||
{ | |||||
value: "3-2-1", | |||||
label: "Level three 3-2-1" | |||||
} | |||||
] | |||||
} | |||||
] | |||||
} | |||||
]; | |||||
const data = ref(sourceData); | |||||
interface FormData { | |||||
[key: string]: any; | |||||
} | |||||
function getFormDefaultValue(): FormData { | |||||
return { | |||||
knowledgeId: undefined, | |||||
isKnowledgeName: 0, | |||||
knowledgeCellName: undefined, | |||||
annotation: undefined | |||||
}; | |||||
} | |||||
//* 方法 | |||||
// 校验规则 | |||||
let formRules = reactive<FormRules>({ | |||||
isKnowledgeName: [ | |||||
{ | |||||
required: true, | |||||
message: "是否做为知识体名称", | |||||
trigger: "change" | |||||
} | |||||
], | |||||
knowledgeCellName: [ | |||||
{ | |||||
required: true, | |||||
message: "请选择上级分类", | |||||
trigger: "change" | |||||
} | |||||
], | |||||
annotation: [{ required: true, message: "分类名称不能为空", trigger: "blur" }] | |||||
}); | |||||
// 取消 | |||||
function handleCancel() { | |||||
dialogVisible.value = false; | |||||
} | |||||
function handleBeforeClose() { | |||||
dialogVisible.value = false; | |||||
const defaultValue = getFormDefaultValue(); | |||||
for (const key of Object.keys(defaultValue)) { | |||||
formData[key] = defaultValue[key]; | |||||
} | |||||
nextTick(formRef.value?.clearValidate); | |||||
} | |||||
//提交 | |||||
function handleSubmit() { | |||||
console.log("提交"); | |||||
ElMessage.success("新增成功"); | |||||
openPromise.value.resolve(); | |||||
dialogVisible.value = false; | |||||
// formRef.value?.validate(async valid => { | |||||
// if (!valid) return; | |||||
// const params = { | |||||
// ...formData | |||||
// }; | |||||
// if (isAdd.value) { | |||||
// await addMenu(params); | |||||
// ElMessage.success("新增成功"); | |||||
// } else { | |||||
// await editMenu(params); | |||||
// ElMessage.success("编辑成功"); | |||||
// } | |||||
// openPromise.value.resolve(); | |||||
// dialogVisible.value = false; | |||||
// } | |||||
} | |||||
function open(params?: FormData) { | |||||
isAdd.value = !params?.knowledgeId; | |||||
dialogVisible.value = true; | |||||
if (params) { | |||||
if (params.knowledgeId) { | |||||
for (const key of Object.keys(formData)) { | |||||
formData[key] = params[key]; | |||||
} | |||||
} else { | |||||
formData.parentId = params.parentId; | |||||
} | |||||
} | |||||
return new Promise(resolve => { | |||||
openPromise.value.resolve = resolve; | |||||
}); | |||||
} | |||||
defineExpose({ | |||||
open | |||||
}); | |||||
</script> |
@@ -2,7 +2,7 @@ | |||||
<div class="main-box"> | <div class="main-box"> | ||||
<div class="class-book"> | <div class="class-book"> | ||||
<div>书目分类</div> | <div>书目分类</div> | ||||
<TreeFilter | |||||
<BookListFilter | |||||
ref="treeFilterRef" | ref="treeFilterRef" | ||||
:request-api="getUserDepartment" | :request-api="getUserDepartment" | ||||
:default-value="initParam.deptId" | :default-value="initParam.deptId" | ||||
@@ -30,19 +30,17 @@ | |||||
</template> | </template> | ||||
</ProTable> | </ProTable> | ||||
<ClassifyDialog ref="dialogRef"></ClassifyDialog> | <ClassifyDialog ref="dialogRef"></ClassifyDialog> | ||||
<BookListDialog ref="dialogRefBookList"></BookListDialog> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="ts" name="BookListManage"> | <script setup lang="ts" name="BookListManage"> | ||||
import { ref, reactive } from "vue"; | import { ref, reactive } from "vue"; | ||||
import { getUserDepartment } from "@/api/modules/system/user"; | import { getUserDepartment } from "@/api/modules/system/user"; | ||||
import TreeFilter from "@/components/TreeFilter/index.vue"; | |||||
import BookListFilter from "@/components/BookListFilter/index.vue"; | |||||
import ProTable from "@/components/ProTable/index.vue"; | import ProTable from "@/components/ProTable/index.vue"; | ||||
import { ProTableInstance, ColumnProps } from "@/components/ProTable/interface"; | import { ProTableInstance, ColumnProps } from "@/components/ProTable/interface"; | ||||
import { Delete, EditPen, Rank, Upload } from "@element-plus/icons-vue"; | import { Delete, EditPen, Rank, Upload } from "@element-plus/icons-vue"; | ||||
import ClassifyDialog from "./components/ClassifyDialog.vue"; | import ClassifyDialog from "./components/ClassifyDialog.vue"; | ||||
import BookListDialog from "./components/BookListDialog.vue"; | |||||
import { useRouter } from "vue-router"; | import { useRouter } from "vue-router"; | ||||
const initParam = reactive({ deptId: "" }); | const initParam = reactive({ deptId: "" }); | ||||
@@ -92,11 +90,6 @@ function viewAction(row) { | |||||
} | } | ||||
}); | }); | ||||
} | } | ||||
// 打开 drawer | |||||
// const dialogRefBookList = ref<InstanceType<typeof BookListDialog> | null>(null); | |||||
// const openDialogBookList = () => { | |||||
// dialogRefBookList.value?.open().then(proTable.value?.getTableList); | |||||
// }; | |||||
</script> | </script> | ||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
.main-box { | .main-box { | ||||
@@ -26,6 +26,11 @@ | |||||
<el-button v-if="false" :icon="CircleClose" round size="large" @click="resetForm(loginFormRef)"> 重置 </el-button> | <el-button v-if="false" :icon="CircleClose" round size="large" @click="resetForm(loginFormRef)"> 重置 </el-button> | ||||
<el-button size="large" type="primary" :loading="loading" @click="login(loginFormRef)"> 登录 </el-button> | <el-button size="large" type="primary" :loading="loading" @click="login(loginFormRef)"> 登录 </el-button> | ||||
</div> | </div> | ||||
<div class="login-tips mt30"> | |||||
<p>温馨提示:</p> | |||||
<p>1、登录时请注意区分登录账号的角色</p> | |||||
<p>2、登录后请完善基本信息并及时修改密码</p> | |||||
</div> | |||||
</template> | </template> | ||||
<script setup lang="ts"> | <script setup lang="ts"> | ||||
@@ -13,69 +13,76 @@ | |||||
flex-direction: column; | flex-direction: column; | ||||
align-items: center; | align-items: center; | ||||
justify-content: center; | justify-content: center; | ||||
.dark { | |||||
position: absolute; | |||||
top: 13px; | |||||
right: 18px; | |||||
} | |||||
.login-logo { | |||||
text-align: center; | |||||
.logo-text { | |||||
margin: 0; | |||||
font-weight: bold; | |||||
} | |||||
h1.logo-text { | |||||
font-family: STSongti-SC-Bold, STSongti-SC; | |||||
font-size: 52px; | |||||
line-height: 73px; | |||||
color: #340d00; | |||||
} | |||||
h2.logo-text { | |||||
font-family: STKaitiSC-Bold, STKaitiSC; | |||||
font-size: 42px; | |||||
line-height: 59px; | |||||
color: #6a330c; | |||||
} | |||||
} | |||||
.login-form { | .login-form { | ||||
width: 300px; | |||||
padding: 55px 66px; | |||||
margin-top: 40px; | |||||
display: flex; | |||||
padding-left: 66px; | |||||
text-align: center; | text-align: center; | ||||
background-image: url("@/assets/images/login_form_bg.png"); | |||||
background-size: 100% 100%; | |||||
.login-form-text { | |||||
width: 220px; | |||||
height: 30px; | |||||
} | |||||
:deep(.el-form-item) { | |||||
margin-top: 26px; | |||||
margin-bottom: 0; | |||||
.el-input__wrapper { | |||||
padding: 0; | |||||
background: transparent; | |||||
border-bottom: 1px solid #dccfc3; | |||||
border-radius: 0; | |||||
box-shadow: none !important; | |||||
.el-input__inner { | |||||
height: 47px; | |||||
font-family: STKaitiSC-Regular, STKaitiSC; | |||||
font-size: 22px; | |||||
&::placeholder { | |||||
color: #cdb299; | |||||
} | |||||
} | |||||
.el-input__suffix { | |||||
.el-input__icon { | |||||
font-size: 20px; | |||||
color: #eeddce; | |||||
} | |||||
} | |||||
background: #ffffff; | |||||
border: 1px solid #9bf4ec; | |||||
border-radius: 24px; | |||||
box-shadow: 17px 34px 51px 0 #2a4c44; | |||||
.login-left { | |||||
display: flex; | |||||
flex: 1; | |||||
flex-direction: column; | |||||
padding-bottom: 100px; | |||||
.login_title { | |||||
width: 412px; | |||||
height: 44px; | |||||
margin-top: 100px; | |||||
margin-bottom: 91px; | |||||
} | } | ||||
&.is-error .el-input__wrapper { | |||||
border-color: var(--el-color-danger); | |||||
.logo { | |||||
width: 517px; | |||||
height: 364px; | |||||
} | } | ||||
} | } | ||||
.login-right { | |||||
flex: 1; | |||||
padding: 86px 84px; | |||||
background: #ecfffd; | |||||
border-left: 1px solid #9bf4ec; | |||||
border-radius: 0 24px 24px 0; | |||||
.login-form-text { | |||||
font-family: STKaitiSC-Regular, STKaitiSC; | |||||
font-size: 27px; | |||||
font-weight: bold; | |||||
color: var(--el-color-primary); | |||||
text-align: left; | |||||
} | |||||
} | |||||
:deep(.el-form) { | |||||
width: 428px; | |||||
} | |||||
// :deep(.el-form-item) { | |||||
// margin-top: 26px; | |||||
// margin-bottom: 0; | |||||
// .el-input__wrapper { | |||||
// padding: 0; | |||||
// background: transparent; | |||||
// border-bottom: 1px solid #dccfc3; | |||||
// border-radius: 0; | |||||
// box-shadow: none !important; | |||||
// .el-input__inner { | |||||
// height: 47px; | |||||
// font-family: STKaitiSC-Regular, STKaitiSC; | |||||
// font-size: 22px; | |||||
// &::placeholder { | |||||
// color: #cdb299; | |||||
// } | |||||
// } | |||||
// .el-input__suffix { | |||||
// .el-input__icon { | |||||
// font-size: 20px; | |||||
// color: #eeddce; | |||||
// } | |||||
// } | |||||
// } | |||||
// &.is-error .el-input__wrapper { | |||||
// border-color: var(--el-color-danger); | |||||
// } | |||||
// } | |||||
.login-code { | .login-code { | ||||
float: right; | float: right; | ||||
margin-left: 30px; | margin-left: 30px; | ||||
@@ -86,21 +93,23 @@ | |||||
} | } | ||||
} | } | ||||
.login-btn { | .login-btn { | ||||
width: 100%; | |||||
margin-top: 48px; | margin-top: 48px; | ||||
margin-bottom: 35px; | margin-bottom: 35px; | ||||
white-space: nowrap; | white-space: nowrap; | ||||
.el-button { | .el-button { | ||||
width: 100%; | width: 100%; | ||||
height: 60px; | |||||
height: 52px; | |||||
font-family: STSongti-SC-Bold, STSongti-SC; | font-family: STSongti-SC-Bold, STSongti-SC; | ||||
font-size: 22px; | font-size: 22px; | ||||
font-weight: bold; | font-weight: bold; | ||||
background: url("@/assets/images/login_form_btn.png"); | |||||
background-size: 100% 100%; | |||||
border: none; | |||||
background: linear-gradient(180deg, #00786c 0%, #07524b 100%); | |||||
border-radius: 6px; | |||||
} | } | ||||
} | } | ||||
.login-tips { | |||||
color: var(--el-color-primary); | |||||
text-align: left; | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -1,14 +1,15 @@ | |||||
<template> | <template> | ||||
<div class="login-container flx-center"> | <div class="login-container flx-center"> | ||||
<div class="login-box"> | <div class="login-box"> | ||||
<!-- <SwitchDark class="dark" /> --> | |||||
<div class="login-logo"> | |||||
<h1 class="logo-text">中国中医科学院针灸研究所</h1> | |||||
<h2 class="logo-text">{{ title }}</h2> | |||||
</div> | |||||
<div class="login-form"> | <div class="login-form"> | ||||
<img class="login-form-text" src="@/assets/images/login_form_text.png" alt="" /> | |||||
<LoginForm /> | |||||
<div class="login-left"> | |||||
<img class="login_title" src="@/assets/images/login_title.png" alt="" /> | |||||
<img class="logo" src="@/assets/images/logo.png" alt="" /> | |||||
</div> | |||||
<div class="login-right"> | |||||
<div class="login-form-text mb40">欢迎登录</div> | |||||
<LoginForm /> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -17,7 +18,7 @@ | |||||
<script setup lang="ts" name="login"> | <script setup lang="ts" name="login"> | ||||
import LoginForm from "./components/LoginForm.vue"; | import LoginForm from "./components/LoginForm.vue"; | ||||
// import SwitchDark from "@/components/SwitchDark/index.vue"; | // import SwitchDark from "@/components/SwitchDark/index.vue"; | ||||
const title = import.meta.env.VITE_GLOB_APP_TITLE; | |||||
// const title = import.meta.env.VITE_GLOB_APP_TITLE; | |||||
</script> | </script> | ||||
<style scoped lang="scss"> | <style scoped lang="scss"> | ||||