Merge branch 'main' of http://62.234.3.186:3000/sxyanzhu/AIManage
commit
3cbf34d55c
|
@ -10,7 +10,7 @@
|
|||
<script>
|
||||
window.isV2=true
|
||||
</script>
|
||||
-->
|
||||
-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
|
|
|
@ -7,7 +7,35 @@ class MenuAPI {
|
|||
*/
|
||||
static getRoutes() {
|
||||
return new Promise((resolve) => {
|
||||
resolve([
|
||||
resolve([
|
||||
{
|
||||
path: "/home",
|
||||
component: "Layout",
|
||||
redirect: "/home/index2",
|
||||
name: "/index2",
|
||||
meta: {
|
||||
title: "数据总览2",
|
||||
icon: "homepage",
|
||||
hidden: false,
|
||||
roles: ["GUEST", "ADMIN", "ADMIN6","data_admin"],
|
||||
alwaysShow: false,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "index2",
|
||||
component: "dashboard/index2",
|
||||
name: "dashboardIndex2",
|
||||
meta: {
|
||||
title: "模型管理",
|
||||
icon: "user",
|
||||
hidden: true,
|
||||
roles: ["ADMIN", "GUEST","data_admin"],
|
||||
keepAlive: true,
|
||||
alwaysShow: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/modelMgr",
|
||||
component: "Layout",
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
<template>
|
||||
<div class="flex" style="height: 100%;align-items: center;">
|
||||
<div style="flex-grow: 1;display: flex;align-items: center;padding-top: 3px;">
|
||||
<span style="position: relative;top:7px;">
|
||||
<img src="@/assets/logojd.png" class="logo-image" />
|
||||
</span>
|
||||
<span class="logo-title" style="font-weight: bold;font-size: 28px;margin-left: auto;margin-right: auto;color:#101010">超异构框架统一管理平台</span>
|
||||
<div style="flex-grow: 1;display: flex;align-items: center;padding-top: 3px;" >
|
||||
<span style="position: relative;" class="logo-small1">
|
||||
<img src="@/assets/logo2.png" class="logo-image" />
|
||||
<span class="logo-title" style="position: absolute;font-weight: bold;font-size: 14px;color: #003F88;left: 0;bottom: -13px;white-space: nowrap;">中国航天</span>
|
||||
</span>
|
||||
<span style="margin-left: 20px;margin-top: 10px;font-size: 12px;font-weight: bold;" class="logo-title2">
|
||||
<div class="logo-title" style="font-weight: bold;font-size: 22px;color:#003F88"> {{ "中国航天某某某某研究院" }}</div>
|
||||
<div >China Aerospace XXXX Research Institute</div>
|
||||
</span>
|
||||
<span class="logo-title" style="font-weight: bold;font-size: 28px;margin-left: auto;margin-right: auto;color:#101010">算法测试验证软件平台</span>
|
||||
</div>
|
||||
<div>
|
||||
<!--全屏 -->
|
||||
|
@ -17,10 +22,10 @@
|
|||
<!-- 用户头像 -->
|
||||
<el-dropdown class="setting-item" trigger="click">
|
||||
<div class="flex-center h100% p10px">
|
||||
<img
|
||||
:src="userStore.user.avatar + '?imageView2/1/w/80/h/80'"
|
||||
<img src="@/assets/images/avatar.png"
|
||||
class="rounded-full mr-10px w24px w24px"
|
||||
/>
|
||||
<!-- :src="userStore.user.avatar + '?imageView2/1/w/80/h/80'" -->
|
||||
<span>{{ userStore.user.username }}</span>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
|
@ -104,6 +109,7 @@ function resetPassword() {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.setting-item {
|
||||
|
@ -119,8 +125,9 @@ function resetPassword() {
|
|||
background: rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
.logo-image {
|
||||
height: 60px;
|
||||
.logo-image {
|
||||
width: 50px;
|
||||
//height: 68px;
|
||||
}
|
||||
.layout-top,
|
||||
.layout-mix {
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
<!-- 接口文档 -->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<iframe
|
||||
src="https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5"
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameborder="0"
|
||||
></iframe>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/** 关闭tag标签 */
|
||||
.app-container {
|
||||
/* 50px = navbar = 50px */
|
||||
height: calc(100vh - 50px);
|
||||
}
|
||||
|
||||
/** 开启tag标签 */
|
||||
.hasTagsView {
|
||||
.app-container {
|
||||
/* 84px = navbar + tags-view = 50px + 34px */
|
||||
height: calc(100vh - 84px);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,27 +0,0 @@
|
|||
<!-- 接口文档 -->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<iframe
|
||||
src="http://vapi.youlai.tech/doc.html"
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameborder="0"
|
||||
></iframe>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/** 关闭tag标签 */
|
||||
.app-container {
|
||||
/* 50px = navbar = 50px */
|
||||
height: calc(100vh - 50px);
|
||||
}
|
||||
|
||||
/** 开启tag标签 */
|
||||
.hasTagsView {
|
||||
.app-container {
|
||||
/* 84px = navbar + tags-view = 50px + 34px */
|
||||
height: calc(100vh - 84px);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,27 +0,0 @@
|
|||
<!-- 接口文档 -->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<iframe
|
||||
src="http://vapi.youlai.tech/swagger-ui.html"
|
||||
width="100%"
|
||||
height="100%"
|
||||
frameborder="0"
|
||||
></iframe>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/** 关闭tag标签 */
|
||||
.app-container {
|
||||
/* 50px = navbar = 50px */
|
||||
height: calc(100vh - 50px);
|
||||
}
|
||||
|
||||
/** 开启tag标签 */
|
||||
.hasTagsView {
|
||||
.app-container {
|
||||
/* 84px = navbar + tags-view = 50px + 34px */
|
||||
height: calc(100vh - 84px);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,146 +0,0 @@
|
|||
import UserAPI from "@/api/user";
|
||||
import type { UserForm } from "@/api/user/model";
|
||||
import type { IModalConfig } from "@/components/PageModal/index.vue";
|
||||
|
||||
const modalConfig: IModalConfig<UserForm> = {
|
||||
pageName: "sys:user",
|
||||
dialog: {
|
||||
title: "新增用户",
|
||||
width: 800,
|
||||
draggable: true,
|
||||
},
|
||||
form: {
|
||||
labelWidth: 100,
|
||||
},
|
||||
formAction: UserAPI.add,
|
||||
beforeSubmit(data) {
|
||||
console.log("提交之前处理", data);
|
||||
},
|
||||
formItems: [
|
||||
{
|
||||
label: "用户名",
|
||||
prop: "username",
|
||||
rules: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入用户名",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "用户昵称",
|
||||
prop: "nickname",
|
||||
rules: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入用户昵称",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "所属部门",
|
||||
prop: "deptId",
|
||||
rules: [{ required: true, message: "所属部门不能为空", trigger: "blur" }],
|
||||
type: "tree-select",
|
||||
attrs: {
|
||||
placeholder: "请选择所属部门",
|
||||
data: [
|
||||
{
|
||||
value: 1,
|
||||
label: "研筑科技",
|
||||
children: [
|
||||
{
|
||||
value: 2,
|
||||
label: "研发部门",
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: "测试部门",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
filterable: true,
|
||||
"check-strictly": true,
|
||||
"render-after-expand": false,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
label: "性别",
|
||||
prop: "gender",
|
||||
attrs: {
|
||||
placeholder: "请选择",
|
||||
},
|
||||
options: [
|
||||
{ label: "男", value: 1 },
|
||||
{ label: "女", value: 2 },
|
||||
{ label: "未知", value: 0 },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "角色",
|
||||
prop: "roleIds",
|
||||
rules: [{ required: true, message: "用户角色不能为空", trigger: "blur" }],
|
||||
type: "select",
|
||||
attrs: {
|
||||
placeholder: "请选择",
|
||||
multiple: true,
|
||||
},
|
||||
options: [
|
||||
{ label: "系统管理员", value: 2 },
|
||||
{ label: "系统管理员1", value: 4 },
|
||||
{ label: "系统管理员2", value: 5 },
|
||||
{ label: "系统管理员3", value: 6 },
|
||||
{ label: "系统管理员4", value: 7 },
|
||||
{ label: "系统管理员5", value: 8 },
|
||||
{ label: "系统管理员6", value: 9 },
|
||||
{ label: "系统管理员7", value: 10 },
|
||||
{ label: "系统管理员8", value: 11 },
|
||||
{ label: "访问游客", value: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "手机号码",
|
||||
prop: "mobile",
|
||||
rules: [
|
||||
{
|
||||
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
||||
message: "请输入正确的手机号码",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
placeholder: "请输入手机号码",
|
||||
maxlength: 11,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "邮箱",
|
||||
prop: "email",
|
||||
rules: [
|
||||
{
|
||||
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
|
||||
message: "请输入正确的邮箱地址",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入邮箱",
|
||||
maxlength: 50,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "状态",
|
||||
prop: "status",
|
||||
type: "radio",
|
||||
options: [
|
||||
{ label: "正常", value: 1 },
|
||||
{ label: "禁用", value: 0 },
|
||||
],
|
||||
initialValue: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default modalConfig;
|
|
@ -1,70 +0,0 @@
|
|||
import UserAPI from "@/api/user";
|
||||
import type { UserQuery } from "@/api/user/model";
|
||||
import type { IContentConfig } from "@/components/PageContent/index.vue";
|
||||
|
||||
const contentConfig: IContentConfig<UserQuery> = {
|
||||
pageName: "sys:user",
|
||||
table: {
|
||||
border: true,
|
||||
highlightCurrentRow: true,
|
||||
},
|
||||
indexAction: function (params) {
|
||||
if ("createAt" in params) {
|
||||
const createAt = params.createAt as string[];
|
||||
params.startTime = createAt[0];
|
||||
params.endTime = createAt[1];
|
||||
delete params.createAt;
|
||||
}
|
||||
return UserAPI.getPage(params);
|
||||
},
|
||||
deleteAction: UserAPI.deleteByIds,
|
||||
exportAction: UserAPI.export,
|
||||
pk: "id",
|
||||
toolbar: [
|
||||
"add",
|
||||
"delete",
|
||||
"export",
|
||||
{
|
||||
name: "import",
|
||||
icon: "upload",
|
||||
text: "导入",
|
||||
auth: "import",
|
||||
},
|
||||
],
|
||||
cols: [
|
||||
{ type: "selection", width: 50, align: "center" },
|
||||
{ label: "编号", align: "center", prop: "id", width: 100, show: false },
|
||||
{ label: "用户名", align: "center", prop: "username" },
|
||||
{ label: "头像", align: "center", prop: "avatar", templet: "image" },
|
||||
{ label: "用户昵称", align: "center", prop: "nickname", width: 120 },
|
||||
{ label: "性别", align: "center", prop: "genderLabel", width: 100 },
|
||||
{ label: "部门", align: "center", prop: "deptName", width: 120 },
|
||||
{ label: "手机号码", align: "center", prop: "mobile", width: 120 },
|
||||
{
|
||||
label: "状态",
|
||||
align: "center",
|
||||
prop: "status",
|
||||
templet: "custom",
|
||||
slotName: "status",
|
||||
},
|
||||
{ label: "创建时间", align: "center", prop: "createTime", width: 180 },
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 220,
|
||||
templet: "tool",
|
||||
operat: [
|
||||
{
|
||||
name: "reset_pwd",
|
||||
auth: "password:reset",
|
||||
icon: "refresh-left",
|
||||
text: "重置密码",
|
||||
},
|
||||
"edit",
|
||||
"delete",
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default contentConfig;
|
|
@ -1,111 +0,0 @@
|
|||
import type { IContentConfig } from "@/components/PageContent/index.vue";
|
||||
|
||||
const contentConfig: IContentConfig = {
|
||||
pageName: "sys:user",
|
||||
table: {
|
||||
showOverflowTooltip: true,
|
||||
},
|
||||
indexAction: function (params) {
|
||||
// console.log("indexAction:", params);
|
||||
return Promise.resolve({
|
||||
total: 2,
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
username: "tom",
|
||||
avatar:
|
||||
"https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
|
||||
percent: 99,
|
||||
price: 10,
|
||||
url: "https://www.baidu.com",
|
||||
icon: "el-icon-setting",
|
||||
gender: 1,
|
||||
status: 1,
|
||||
status2: 1,
|
||||
createTime: 1715647982437,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
username: "jerry",
|
||||
avatar:
|
||||
"https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
|
||||
percent: 88,
|
||||
price: 999,
|
||||
url: "https://www.google.com",
|
||||
icon: "el-icon-user",
|
||||
gender: 0,
|
||||
status: 0,
|
||||
status2: 0,
|
||||
createTime: 1715648977426,
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
modifyAction(data) {
|
||||
// console.log("modifyAction:", data);
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
cols: [
|
||||
{ type: "selection", width: 50, align: "center" },
|
||||
{ label: "ID", align: "center", prop: "id", show: false },
|
||||
{ label: "用户名", align: "center", prop: "username" },
|
||||
{ label: "图片", align: "center", prop: "avatar", templet: "image" },
|
||||
{
|
||||
label: "百分比",
|
||||
align: "center",
|
||||
prop: "percent",
|
||||
templet: "percent",
|
||||
},
|
||||
{
|
||||
label: "价格",
|
||||
align: "center",
|
||||
prop: "price",
|
||||
templet: "price",
|
||||
priceFormat: "$",
|
||||
},
|
||||
{ label: "链接", align: "center", prop: "url", width: 180, templet: "url" },
|
||||
{ label: "图标", align: "center", prop: "icon", templet: "icon" },
|
||||
{
|
||||
label: "列表值",
|
||||
align: "center",
|
||||
prop: "gender",
|
||||
templet: "list",
|
||||
selectList: { 0: "女", 1: "男" },
|
||||
},
|
||||
{
|
||||
label: "自定义",
|
||||
align: "center",
|
||||
prop: "status",
|
||||
templet: "custom",
|
||||
slotName: "status",
|
||||
},
|
||||
{
|
||||
label: "状态",
|
||||
align: "center",
|
||||
prop: "status2",
|
||||
templet: "switch",
|
||||
activeValue: 1,
|
||||
inactiveValue: 0,
|
||||
activeText: "启用",
|
||||
inactiveText: "禁用",
|
||||
},
|
||||
{
|
||||
label: "创建时间",
|
||||
align: "center",
|
||||
prop: "createTime",
|
||||
minWidth: 120,
|
||||
templet: "date",
|
||||
dateFormat: "YYYY/MM/DD HH:mm:ss",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
align: "center",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
templet: "tool",
|
||||
operat: ["edit", "delete"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default contentConfig;
|
|
@ -1,146 +0,0 @@
|
|||
import UserAPI from "@/api/user";
|
||||
import type { UserForm } from "@/api/user/model";
|
||||
import type { IModalConfig } from "@/components/PageModal/index.vue";
|
||||
|
||||
const modalConfig: IModalConfig<UserForm> = {
|
||||
pageName: "sys:user",
|
||||
pk: "id",
|
||||
component: "drawer",
|
||||
drawer: {
|
||||
title: "修改用户",
|
||||
size: 300,
|
||||
},
|
||||
formAction: function (data) {
|
||||
return UserAPI.update(data.id as number, data);
|
||||
},
|
||||
beforeSubmit(data) {
|
||||
console.log("提交之前处理", data);
|
||||
},
|
||||
formItems: [
|
||||
{
|
||||
label: "用户名",
|
||||
prop: "username",
|
||||
rules: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入用户名",
|
||||
readonly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "用户昵称",
|
||||
prop: "nickname",
|
||||
rules: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入用户昵称",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "所属部门",
|
||||
prop: "deptId",
|
||||
rules: [{ required: true, message: "所属部门不能为空", trigger: "blur" }],
|
||||
type: "tree-select",
|
||||
attrs: {
|
||||
placeholder: "请选择所属部门",
|
||||
data: [
|
||||
{
|
||||
value: 1,
|
||||
label: "研筑科技",
|
||||
children: [
|
||||
{
|
||||
value: 2,
|
||||
label: "研发部门",
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: "测试部门",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
filterable: true,
|
||||
"check-strictly": true,
|
||||
"render-after-expand": false,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
label: "性别",
|
||||
prop: "gender",
|
||||
attrs: {
|
||||
placeholder: "请选择",
|
||||
},
|
||||
options: [
|
||||
{ label: "男", value: 1 },
|
||||
{ label: "女", value: 2 },
|
||||
{ label: "未知", value: 0 },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "角色",
|
||||
prop: "roleIds",
|
||||
rules: [{ required: true, message: "用户角色不能为空", trigger: "blur" }],
|
||||
type: "select",
|
||||
attrs: {
|
||||
placeholder: "请选择",
|
||||
multiple: true,
|
||||
},
|
||||
options: [
|
||||
{ label: "系统管理员", value: 2 },
|
||||
{ label: "系统管理员1", value: 4 },
|
||||
{ label: "系统管理员2", value: 5 },
|
||||
{ label: "系统管理员3", value: 6 },
|
||||
{ label: "系统管理员4", value: 7 },
|
||||
{ label: "系统管理员5", value: 8 },
|
||||
{ label: "系统管理员6", value: 9 },
|
||||
{ label: "系统管理员7", value: 10 },
|
||||
{ label: "系统管理员8", value: 11 },
|
||||
{ label: "访问游客", value: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
label: "手机号码",
|
||||
prop: "mobile",
|
||||
rules: [
|
||||
{
|
||||
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
||||
message: "请输入正确的手机号码",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
placeholder: "请输入手机号码",
|
||||
maxlength: 11,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "邮箱",
|
||||
prop: "email",
|
||||
rules: [
|
||||
{
|
||||
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
|
||||
message: "请输入正确的邮箱地址",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
type: "input",
|
||||
attrs: {
|
||||
placeholder: "请输入邮箱",
|
||||
maxlength: 50,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "状态",
|
||||
prop: "status",
|
||||
type: "radio",
|
||||
options: [
|
||||
{ label: "正常", value: 1 },
|
||||
{ label: "禁用", value: 0 },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default modalConfig;
|
|
@ -1,83 +0,0 @@
|
|||
import type { ISearchConfig } from "@/components/PageSearch/index.vue";
|
||||
|
||||
const searchConfig: ISearchConfig = {
|
||||
pageName: "sys:user",
|
||||
formItems: [
|
||||
{
|
||||
type: "input",
|
||||
label: "关键字",
|
||||
prop: "keywords",
|
||||
attrs: {
|
||||
placeholder: "用户名/昵称/手机号",
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "200px",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "tree-select",
|
||||
label: "部门",
|
||||
prop: "deptId",
|
||||
attrs: {
|
||||
placeholder: "请选择",
|
||||
data: [
|
||||
{
|
||||
value: 1,
|
||||
label: "研筑科技",
|
||||
children: [
|
||||
{
|
||||
value: 2,
|
||||
label: "研发部门",
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: "测试部门",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
filterable: true,
|
||||
"check-strictly": true,
|
||||
"render-after-expand": false,
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "150px",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
label: "状态",
|
||||
prop: "status",
|
||||
attrs: {
|
||||
placeholder: "全部",
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "100px",
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{ label: "启用", value: 1 },
|
||||
{ label: "禁用", value: 0 },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "date-picker",
|
||||
label: "创建时间",
|
||||
prop: "createAt",
|
||||
attrs: {
|
||||
type: "daterange",
|
||||
"range-separator": "~",
|
||||
"start-placeholder": "开始时间",
|
||||
"end-placeholder": "截止时间",
|
||||
"value-format": "YYYY-MM-DD",
|
||||
style: {
|
||||
width: "240px",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default searchConfig;
|
|
@ -1,111 +0,0 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-link
|
||||
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/curd/index.vue"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
class="mb-10"
|
||||
>
|
||||
示例源码 请点击>>>>
|
||||
</el-link>
|
||||
|
||||
<!-- 搜索 -->
|
||||
<page-search
|
||||
ref="searchRef"
|
||||
:search-config="searchConfig"
|
||||
@query-click="handleQueryClick"
|
||||
@reset-click="handleResetClick"
|
||||
/>
|
||||
|
||||
<!-- 列表 -->
|
||||
<page-content
|
||||
ref="contentRef"
|
||||
:content-config="contentConfig"
|
||||
@add-click="handleAddClick"
|
||||
@edit-click="handleEditClick"
|
||||
@export-click="handleExportClick"
|
||||
@search-click="handleSearchClick"
|
||||
@toolbar-click="handleToolbarClick"
|
||||
@operat-click="handleOperatClick"
|
||||
>
|
||||
<template #status="scope">
|
||||
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</page-content>
|
||||
|
||||
<!-- 新增 -->
|
||||
<page-modal
|
||||
ref="addModalRef"
|
||||
:modal-config="addModalConfig"
|
||||
@submit-click="handleSubmitClick"
|
||||
/>
|
||||
|
||||
<!-- 编辑 -->
|
||||
<page-modal
|
||||
ref="editModalRef"
|
||||
:modal-config="editModalConfig"
|
||||
@submit-click="handleSubmitClick"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UserAPI from "@/api/user";
|
||||
import type { IObject, IOperatData } from "@/hooks/usePage";
|
||||
import usePage from "@/hooks/usePage";
|
||||
import addModalConfig from "./config/add";
|
||||
import contentConfig from "./config/content";
|
||||
import editModalConfig from "./config/edit";
|
||||
import searchConfig from "./config/search";
|
||||
|
||||
const {
|
||||
searchRef,
|
||||
contentRef,
|
||||
addModalRef,
|
||||
editModalRef,
|
||||
handleQueryClick,
|
||||
handleResetClick,
|
||||
handleAddClick,
|
||||
// handleEditClick,
|
||||
handleSubmitClick,
|
||||
handleExportClick,
|
||||
handleSearchClick,
|
||||
} = usePage();
|
||||
// 编辑
|
||||
async function handleEditClick(row: IObject) {
|
||||
// 根据id获取数据进行填充
|
||||
const data = await UserAPI.getFormData(row.id);
|
||||
editModalRef.value?.setModalVisible(data);
|
||||
}
|
||||
// 其他工具栏
|
||||
function handleToolbarClick(name: string) {
|
||||
console.log(name);
|
||||
if (name === "import") {
|
||||
ElMessage.success("点击了导入按钮");
|
||||
}
|
||||
}
|
||||
// 其他操作列
|
||||
function handleOperatClick(data: IOperatData) {
|
||||
console.log(data);
|
||||
// 重置密码
|
||||
if (data.name === "reset_pwd") {
|
||||
ElMessageBox.prompt(
|
||||
"请输入用户「" + data.row.username + "」的新密码",
|
||||
"重置密码",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
}
|
||||
).then(({ value }) => {
|
||||
if (!value) {
|
||||
ElMessage.warning("请输入新密码");
|
||||
return false;
|
||||
}
|
||||
// 发送网络请求
|
||||
ElMessage.success("密码重置成功,新密码是:" + value);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,32 +0,0 @@
|
|||
<!-- 字典组件示例 -->
|
||||
<script setup lang="ts">
|
||||
const stringValue = ref("1"); // 性别(值为String)
|
||||
const numberValue = ref(1); // 性别(值为Number)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-link
|
||||
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/dict.vue"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
class="mb-[20px]"
|
||||
>示例源码 请点击>>>></el-link
|
||||
>
|
||||
<el-form>
|
||||
<el-form-item label="性别">
|
||||
<dictionary v-model="stringValue" type-code="gender" />
|
||||
<el-link :underline="false" type="primary" class="ml-5"
|
||||
>值为String: const value = ref("1");
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="性别">
|
||||
<dictionary v-model="numberValue" type-code="gender" />
|
||||
<el-link :underline="false" type="success" class="ml-5"
|
||||
>值为Number: const value = ref(1);
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
|
@ -1,17 +0,0 @@
|
|||
<!-- 图标选择器示例 -->
|
||||
<script setup lang="ts">
|
||||
const iconName = ref("edit");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-link
|
||||
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/icon-selector.vue"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
class="mb-10"
|
||||
>示例源码 请点击>>>></el-link
|
||||
>
|
||||
<icon-select v-model="iconName" />
|
||||
</div>
|
||||
</template>
|
|
@ -1,156 +0,0 @@
|
|||
<template>
|
||||
<div class="icons-container">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="Icons">
|
||||
<div class="grid">
|
||||
<div
|
||||
v-for="item of svg_icons"
|
||||
:key="item"
|
||||
@click="handleClipboard(generateIconCode(item), $event)"
|
||||
>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="generateIconCode(item)"
|
||||
placement="top"
|
||||
>
|
||||
<div class="icon-item">
|
||||
<svg-icon :icon-class="item" />
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Element-UI Icons">
|
||||
<div class="grid">
|
||||
<div
|
||||
v-for="(icon, name) of icons"
|
||||
:key="name"
|
||||
@click="handleClipboard(generateElementIconCode(name), $event)"
|
||||
>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="generateElementIconCode(name)"
|
||||
placement="top"
|
||||
>
|
||||
<div class="icon-item">
|
||||
<el-icon :size="20">
|
||||
<component :is="icon" />
|
||||
</el-icon>
|
||||
<span>{{ name }}</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgIcon from "@/components/SvgIcon/index.vue";
|
||||
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
|
||||
|
||||
defineOptions({
|
||||
// eslint-disable-next-line
|
||||
name: "Icons",
|
||||
inheritAttrs: false,
|
||||
});
|
||||
const svg_icons: string[] = [
|
||||
"api",
|
||||
"cascader",
|
||||
"client",
|
||||
"close",
|
||||
"close_all",
|
||||
"close_left",
|
||||
"close_other",
|
||||
"close_right",
|
||||
"dict",
|
||||
"document",
|
||||
"download",
|
||||
"drag",
|
||||
"edit",
|
||||
"exit-fullscreen",
|
||||
"eye-open",
|
||||
"eye",
|
||||
"fullscreen",
|
||||
"github",
|
||||
"homepage",
|
||||
"language",
|
||||
"link",
|
||||
"menu",
|
||||
"message",
|
||||
"money",
|
||||
"monitor",
|
||||
"order",
|
||||
"password",
|
||||
"peoples",
|
||||
"perm",
|
||||
"publish",
|
||||
"role",
|
||||
"security",
|
||||
"size",
|
||||
"skill",
|
||||
"system",
|
||||
"tree",
|
||||
"user",
|
||||
"uv",
|
||||
"verify-code",
|
||||
];
|
||||
const icons = ref(ElementPlusIconsVue);
|
||||
|
||||
const { copy } = useClipboard();
|
||||
|
||||
function generateIconCode(symbol: any) {
|
||||
return `<svg-icon icon-class="${symbol}" />`;
|
||||
}
|
||||
|
||||
function generateElementIconCode(symbol: any) {
|
||||
return `<el-icon><${symbol} /></el-icon>`;
|
||||
}
|
||||
|
||||
function handleClipboard(text: any, event: any) {
|
||||
// clipboard(text, event);
|
||||
copy(text)
|
||||
.then(() => {
|
||||
ElMessage.success("Copy successfully");
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.warning("Copy failed");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.icons-container {
|
||||
margin: 10px 20px 0;
|
||||
overflow: hidden;
|
||||
|
||||
.grid {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
}
|
||||
|
||||
.icon-item {
|
||||
float: left;
|
||||
width: 100px;
|
||||
height: 85px;
|
||||
margin: 20px;
|
||||
font-size: 30px;
|
||||
color: var(--el-text-color-regular);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,28 +0,0 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<iframe
|
||||
src="https://juejin.cn/post/7228990409909108793"
|
||||
frameborder="0"
|
||||
></iframe>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
/** 关闭tag标签 */
|
||||
.app-container {
|
||||
/* 50px = navbar = 50px */
|
||||
height: calc(100vh - 50px);
|
||||
}
|
||||
|
||||
/** 开启tag标签 */
|
||||
.hasTagsView {
|
||||
.app-container {
|
||||
/* 84px = navbar + tags-view = 50px + 34px */
|
||||
height: calc(100vh - 84px);
|
||||
}
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -1,5 +0,0 @@
|
|||
<template>
|
||||
<div style="padding: 30px">
|
||||
<el-alert :closable="false" title="菜单三级-1" type="error" />
|
||||
</div>
|
||||
</template>
|
|
@ -1,5 +0,0 @@
|
|||
<template>
|
||||
<div style="padding: 30px">
|
||||
<el-alert :closable="false" title="菜单三级-2" type="warning" />
|
||||
</div>
|
||||
</template>
|
|
@ -1,7 +0,0 @@
|
|||
<template>
|
||||
<div style="padding: 30px">
|
||||
<el-alert :closable="false" title="菜单二级" type="success">
|
||||
<router-view />
|
||||
</el-alert>
|
||||
</div>
|
||||
</template>
|
|
@ -1,15 +0,0 @@
|
|||
<template>
|
||||
<div style="padding: 30px">
|
||||
<el-link
|
||||
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/multi-level/level1.vue"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
class="mb-10"
|
||||
>示例源码 请点击>>>></el-link
|
||||
>
|
||||
|
||||
<el-alert :closable="false" title="菜单一级">
|
||||
<router-view />
|
||||
</el-alert>
|
||||
</div>
|
||||
</template>
|
|
@ -1,186 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import FileAPI from "@/api/file";
|
||||
|
||||
const imgUrl = ref("");
|
||||
const canvas = ref();
|
||||
let ctx: CanvasRenderingContext2D;
|
||||
|
||||
// 正在绘制中,用来控制 move 和 end 事件
|
||||
let painting = false;
|
||||
|
||||
// 获取触发点相对被触发dom的左、上角距离
|
||||
const getOffset = (event: MouseEvent | TouchEvent) => {
|
||||
let offset: [number, number];
|
||||
if ((event as MouseEvent).offsetX) {
|
||||
// pc端
|
||||
const { offsetX, offsetY } = event as MouseEvent;
|
||||
offset = [offsetX, offsetY];
|
||||
} else {
|
||||
// 移动端
|
||||
const { top, left } = canvas.value.getBoundingClientRect();
|
||||
const offsetX = (event as TouchEvent).touches[0].clientX - left;
|
||||
const offsetY = (event as TouchEvent).touches[0].clientY - top;
|
||||
offset = [offsetX, offsetY];
|
||||
}
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
// 绘制起点
|
||||
let startX = 0,
|
||||
startY = 0;
|
||||
|
||||
// 鼠标/触摸 按下时,保存 触发点相对被触发dom的左、上 距离
|
||||
const onEventStart = (event: MouseEvent | TouchEvent) => {
|
||||
[startX, startY] = getOffset(event);
|
||||
painting = true;
|
||||
};
|
||||
|
||||
const onEventMove = (event: MouseEvent | TouchEvent) => {
|
||||
if (painting) {
|
||||
// 鼠标/触摸 移动时,保存 移动点相对 被触发dom的左、上 距离
|
||||
const [endX, endY] = getOffset(event);
|
||||
paint(startX, startY, endX, endY, ctx);
|
||||
|
||||
// 每次绘制 或 清除结束后,起点要重置为上次的终点
|
||||
startX = endX;
|
||||
startY = endY;
|
||||
}
|
||||
};
|
||||
|
||||
const onEventEnd = () => {
|
||||
if (painting) {
|
||||
painting = false; // 停止绘制
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
ctx = canvas.value.getContext("2d") as CanvasRenderingContext2D;
|
||||
});
|
||||
const handleToFile = async () => {
|
||||
if (isCanvasBlank(canvas.value)) {
|
||||
ElMessage({
|
||||
type: "warning",
|
||||
message: "当前签名文件为空",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const file = dataURLtoFile(canvas.value.toDataURL(), "签名.png");
|
||||
|
||||
if (!file) return;
|
||||
const data = await FileAPI.upload(file);
|
||||
handleClearSign();
|
||||
imgUrl.value = data.url;
|
||||
};
|
||||
const handleClearSign = () => {
|
||||
ctx.clearRect(0, 0, canvas.value.width, canvas.value.height);
|
||||
};
|
||||
const isCanvasBlank = (canvas: HTMLCanvasElement) => {
|
||||
const blank = document.createElement("canvas"); //系统获取一个空canvas对象
|
||||
blank.width = canvas.width;
|
||||
blank.height = canvas.height;
|
||||
return canvas.toDataURL() == blank.toDataURL(); //比较值相等则为空
|
||||
};
|
||||
|
||||
// 保存为图片
|
||||
const handleSaveImg = () => {
|
||||
if (isCanvasBlank(canvas.value)) {
|
||||
ElMessage({
|
||||
type: "warning",
|
||||
message: "当前签名文件为空",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const el = document.createElement("a");
|
||||
// 设置 href 为图片经过 base64 编码后的字符串,默认为 png 格式
|
||||
el.href = canvas.value.toDataURL();
|
||||
el.download = "签名";
|
||||
// 创建一个点击事件并对 a 标签进行触发
|
||||
const event = new MouseEvent("click");
|
||||
el.dispatchEvent(event);
|
||||
};
|
||||
// 转为file格式,可传递给后端
|
||||
const dataURLtoFile = (dataurl: string, filename: string) => {
|
||||
const arr: string[] = dataurl.split(",");
|
||||
if (!arr.length) return;
|
||||
|
||||
const mime = arr[0].match(/:(.*?);/);
|
||||
if (mime) {
|
||||
const bstr = atob(arr[1]);
|
||||
let n = bstr.length;
|
||||
const u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
return new File([u8arr], filename, { type: mime[1] });
|
||||
}
|
||||
};
|
||||
// canvas 画图
|
||||
function paint(
|
||||
startX: number,
|
||||
startY: number,
|
||||
endX: number,
|
||||
endY: number,
|
||||
ctx: CanvasRenderingContext2D
|
||||
) {
|
||||
ctx.beginPath();
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeStyle = "#000";
|
||||
ctx.moveTo(startX, startY);
|
||||
ctx.lineTo(endX, endY);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="canvas-dom">
|
||||
<h3>基于canvas实现的签名组件</h3>
|
||||
<header>
|
||||
<el-button type="primary" @click="handleSaveImg">保存为图片</el-button>
|
||||
<el-button @click="handleToFile"> 保存到后端 </el-button>
|
||||
<el-button @click="handleClearSign"> 清空签名 </el-button>
|
||||
</header>
|
||||
<canvas
|
||||
ref="canvas"
|
||||
height="200"
|
||||
width="500"
|
||||
@mousedown="onEventStart"
|
||||
@mousemove.stop.prevent="onEventMove"
|
||||
@mouseup="onEventEnd"
|
||||
@touchstart="onEventStart"
|
||||
@touchmove.stop.prevent="onEventMove"
|
||||
@touchend="onEventEnd"
|
||||
>
|
||||
</canvas>
|
||||
<img v-if="imgUrl" :src="imgUrl" alt="签名" />
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.canvas-dom {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
background-color: #fff;
|
||||
|
||||
canvas {
|
||||
border: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin: 8px;
|
||||
|
||||
.eraser-option {
|
||||
display: flex;
|
||||
|
||||
label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,112 +0,0 @@
|
|||
import UserAPI from "@/api/user";
|
||||
import type { ISelectConfig } from "@/components/TableSelect/index.vue";
|
||||
|
||||
const selectConfig: ISelectConfig = {
|
||||
pk: "id",
|
||||
width: "70%",
|
||||
placeholder: "请选择用户",
|
||||
formItems: [
|
||||
{
|
||||
type: "input",
|
||||
label: "关键字",
|
||||
prop: "keywords",
|
||||
attrs: {
|
||||
placeholder: "用户名/昵称/手机号",
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "200px",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "tree-select",
|
||||
label: "部门",
|
||||
prop: "deptId",
|
||||
attrs: {
|
||||
placeholder: "请选择",
|
||||
data: [
|
||||
{
|
||||
value: 1,
|
||||
label: "研筑科技",
|
||||
children: [
|
||||
{
|
||||
value: 2,
|
||||
label: "研发部门",
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: "测试部门",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
filterable: true,
|
||||
"check-strictly": true,
|
||||
"render-after-expand": false,
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "150px",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
label: "状态",
|
||||
prop: "status",
|
||||
attrs: {
|
||||
placeholder: "全部",
|
||||
clearable: true,
|
||||
style: {
|
||||
width: "100px",
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{ label: "启用", value: 1 },
|
||||
{ label: "禁用", value: 0 },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "date-picker",
|
||||
label: "创建时间",
|
||||
prop: "createAt",
|
||||
attrs: {
|
||||
type: "daterange",
|
||||
"range-separator": "~",
|
||||
"start-placeholder": "开始时间",
|
||||
"end-placeholder": "截止时间",
|
||||
"value-format": "YYYY-MM-DD",
|
||||
style: {
|
||||
width: "240px",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
indexAction: function (params) {
|
||||
if ("createAt" in params) {
|
||||
const createAt = params.createAt as string[];
|
||||
params.startTime = createAt[0];
|
||||
params.endTime = createAt[1];
|
||||
delete params.createAt;
|
||||
}
|
||||
return UserAPI.getPage(params);
|
||||
},
|
||||
tableColumns: [
|
||||
{ type: "selection", width: 50, align: "center" },
|
||||
{ label: "编号", align: "center", prop: "id", width: 100 },
|
||||
{ label: "用户名", align: "center", prop: "username" },
|
||||
{ label: "用户昵称", align: "center", prop: "nickname", width: 120 },
|
||||
{ label: "性别", align: "center", prop: "genderLabel", width: 100 },
|
||||
{ label: "部门", align: "center", prop: "deptName", width: 120 },
|
||||
{ label: "手机号码", align: "center", prop: "mobile", width: 120 },
|
||||
{
|
||||
label: "状态",
|
||||
align: "center",
|
||||
prop: "status",
|
||||
templet: "custom",
|
||||
slotName: "status",
|
||||
},
|
||||
{ label: "创建时间", align: "center", prop: "createTime", width: 180 },
|
||||
],
|
||||
};
|
||||
|
||||
export default selectConfig;
|
|
@ -1,51 +0,0 @@
|
|||
<!-- 列表选择器示例 -->
|
||||
<script setup lang="ts">
|
||||
import selectConfig from "./config/select";
|
||||
|
||||
interface IUser {
|
||||
id: number;
|
||||
username: string;
|
||||
nickname: string;
|
||||
mobile: string;
|
||||
genderLabel: string;
|
||||
avatar: string;
|
||||
email: string | null;
|
||||
status: number;
|
||||
deptName: string;
|
||||
roleNames: string;
|
||||
createTime: string;
|
||||
}
|
||||
const selectedUser = ref<IUser>();
|
||||
function handleConfirm(data: IUser[]) {
|
||||
selectedUser.value = data[0];
|
||||
}
|
||||
const text = computed(() => {
|
||||
return selectedUser.value
|
||||
? `${selectedUser.value.username} - ${selectedUser.value.genderLabel} - ${selectedUser.value.deptName}`
|
||||
: "";
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-link
|
||||
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/table-select/index.vue"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
class="mb-10"
|
||||
>
|
||||
示例源码 请点击>>>>
|
||||
</el-link>
|
||||
<table-select
|
||||
:text="text"
|
||||
:select-config="selectConfig"
|
||||
@confirm-click="handleConfirm"
|
||||
>
|
||||
<template #status="scope">
|
||||
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</table-select>
|
||||
</div>
|
||||
</template>
|
|
@ -1,37 +0,0 @@
|
|||
<!-- 文件上传组件(单图+多图)示例 -->
|
||||
<script setup lang="ts">
|
||||
import SingleUpload from "@/components/Upload/SingleUpload.vue";
|
||||
import MultiUpload from "@/components/Upload/MultiUpload.vue";
|
||||
|
||||
const singlePicUrl = ref(
|
||||
"https://oss.youlai.tech/youlai-boot/2023/05/20/2b6d8b49fa1047348a0a41cef5aaf69e.gif"
|
||||
);
|
||||
// 这里放外链图片,防止被删
|
||||
const multiPicUrls = ref([
|
||||
"https://s2.loli.net/2023/05/24/yNsxFC8rLHMZQcK.jpg",
|
||||
"https://s2.loli.net/2023/05/24/RuHFMwW4rG5lIqs.jpg",
|
||||
"https://s2.loli.net/2023/05/24/ZPiGbcpR91WqInB.jpg",
|
||||
"https://s2.loli.net/2023/05/24/e1bcnEq3MFdmlNL.jpg",
|
||||
"https://s2.loli.net/2023/05/24/wZTSPj1yDQNcuhU.jpg",
|
||||
]);
|
||||
</script>
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-link
|
||||
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/upload.vue"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
class="mb-10"
|
||||
>示例源码 请点击>>>></el-link
|
||||
>
|
||||
|
||||
<el-form>
|
||||
<el-form-item label="单图上传">
|
||||
<single-upload v-model="singlePicUrl" />
|
||||
</el-form-item>
|
||||
<el-form-item label="多图上传">
|
||||
<multi-upload v-model="multiPicUrls" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
|
@ -1,19 +0,0 @@
|
|||
<!-- wangEditor富文本编辑器示例 -->
|
||||
<script setup lang="ts">
|
||||
import Editor from "@/components/WangEditor/index.vue";
|
||||
|
||||
const value = ref("初始内容");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-link
|
||||
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/wang-editor.vue"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
class="mb-[20px]"
|
||||
>示例源码 请点击>>>></el-link
|
||||
>
|
||||
<editor v-model="value" style="height: calc(100vh - 180px)" />
|
||||
</div>
|
||||
</template>
|
|
@ -1,268 +0,0 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-link
|
||||
href="https://gitee.com/youlaiorg/vue3-element-admin/blob/master/src/views/demo/websocket.vue"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
class="mb-[20px]"
|
||||
>示例源码 请点击>>>></el-link
|
||||
>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-card>
|
||||
<el-row>
|
||||
<el-col :span="16">
|
||||
<el-input v-model="socketEndpoint" class="w-220px" />
|
||||
<el-button
|
||||
type="primary"
|
||||
class="ml-5"
|
||||
@click="connectWebSocket"
|
||||
:disabled="isConnected"
|
||||
>连接</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
@click="disconnectWebSocket"
|
||||
:disabled="!isConnected"
|
||||
>断开</el-button
|
||||
>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8" class="text-right">
|
||||
连接状态:
|
||||
<el-tag class="ml-2" type="success" v-if="isConnected"
|
||||
>已连接</el-tag
|
||||
>
|
||||
<el-tag class="ml-2" type="info" v-else>已断开</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt-5">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="消息内容">
|
||||
<el-input type="textarea" v-model="topicMessage" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button @click="sendToAll" type="primary">发送广播</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt-5">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="消息内容">
|
||||
<el-input type="textarea" v-model="queneMessage" />
|
||||
</el-form-item>
|
||||
<el-form-item label="消息接收人">
|
||||
<el-input v-model="receiver" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="sendToUser" type="primary"
|
||||
>发送点对点消息</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-card>
|
||||
<div class="message-container">
|
||||
<div
|
||||
v-for="(message, index) in messages"
|
||||
:key="index"
|
||||
:class="{
|
||||
'tip-message': message.type === 'tip',
|
||||
message: message.type !== 'tip',
|
||||
'message--sent': message.sender === userStore.user.username,
|
||||
'message--received': message.sender !== userStore.user.username,
|
||||
}"
|
||||
>
|
||||
<div v-if="message.type != 'tip'" class="message-content">
|
||||
<div
|
||||
:class="{
|
||||
'message-sender':
|
||||
message.sender === userStore.user.username,
|
||||
'message-receiver':
|
||||
message.sender !== userStore.user.username,
|
||||
}"
|
||||
>
|
||||
{{ message.sender }}
|
||||
</div>
|
||||
<div class="color-#333">{{ message.content }}</div>
|
||||
</div>
|
||||
<div v-else>{{ message.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- websocket 示例 -->
|
||||
<script setup lang="ts">
|
||||
import SockJS from "sockjs-client/dist/sockjs.min.js";
|
||||
//import SockJS from "sockjs-client";
|
||||
import Stomp from "stompjs";
|
||||
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import { TOKEN_KEY } from "@/enums/CacheEnum";
|
||||
|
||||
const userStore = useUserStoreHook();
|
||||
|
||||
const isConnected = ref(false);
|
||||
// const socketEndpoint = ref("http://47.117.115.107:8989/ws"); // 线上
|
||||
const socketEndpoint = ref("http://localhost:8989/ws"); // 本地
|
||||
|
||||
const receiver = ref("root");
|
||||
|
||||
interface MessageType {
|
||||
type?: string; // 消息类型: tip-提示消息
|
||||
sender?: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
const messages = ref<MessageType[]>([]);
|
||||
|
||||
const topicMessage = ref(
|
||||
"亲爱的大冤种们,由于一只史诗级的BUG,系统版本已经被迫回退到了0.0.1。"
|
||||
); // 广播消息
|
||||
|
||||
const queneMessage = ref(
|
||||
"hi , " +
|
||||
receiver.value +
|
||||
" , 我是" +
|
||||
userStore.user.username +
|
||||
" , 想和你交个朋友 ! "
|
||||
);
|
||||
|
||||
function sendToAll() {
|
||||
stompClient.send("/app/sendToAll", {}, topicMessage.value);
|
||||
messages.value.push({
|
||||
sender: userStore.user.username,
|
||||
content: topicMessage.value,
|
||||
});
|
||||
}
|
||||
|
||||
function sendToUser() {
|
||||
stompClient.send("/app/sendToUser/" + receiver.value, {}, queneMessage.value);
|
||||
messages.value.push({
|
||||
sender: userStore.user.username,
|
||||
content: queneMessage.value,
|
||||
});
|
||||
}
|
||||
|
||||
let stompClient: Stomp.Client;
|
||||
|
||||
function connectWebSocket() {
|
||||
let socket = new SockJS(socketEndpoint.value);
|
||||
|
||||
stompClient = Stomp.over(socket);
|
||||
|
||||
stompClient.connect(
|
||||
{ Authorization: localStorage.getItem(TOKEN_KEY) },
|
||||
() => {
|
||||
isConnected.value = true;
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: "Websocket 已连接",
|
||||
type: "tip",
|
||||
});
|
||||
|
||||
stompClient.subscribe("/topic/notice", (res: any) => {
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: res.body,
|
||||
});
|
||||
});
|
||||
|
||||
stompClient.subscribe("/user/queue/greeting", (res) => {
|
||||
const messageData = JSON.parse(res.body) as MessageType;
|
||||
messages.value.push({
|
||||
sender: messageData.sender,
|
||||
content: messageData.content,
|
||||
});
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
console.log("连接失败: " + error);
|
||||
isConnected.value = false; // 更新连接状态
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: "Websocket 已断开",
|
||||
type: "tip",
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function disconnectWebSocket() {
|
||||
if (stompClient && stompClient.connected) {
|
||||
stompClient.disconnect(() => {
|
||||
isConnected.value = false; // 更新连接状态
|
||||
messages.value.push({
|
||||
sender: "Server",
|
||||
content: "Websocket 已断开",
|
||||
type: "tip",
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
connectWebSocket();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.message-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.message--sent {
|
||||
align-self: flex-end;
|
||||
background-color: #dcf8c6;
|
||||
}
|
||||
|
||||
.message--received {
|
||||
align-self: flex-start;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.message-sender {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.message-receiver {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tip-message {
|
||||
align-self: center;
|
||||
padding: 5px 10px;
|
||||
margin-bottom: 5px;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
|
@ -1,198 +0,0 @@
|
|||
<template>
|
||||
<div class="flow-demo1">
|
||||
<div style="display: flex;height:100%">
|
||||
<NodePanel :lf="lf" ref="nodePanel" class="node-panel"/>
|
||||
<el-card class="flow-card">
|
||||
<div ref="flow" class="viewport" id="flowMain" @click="hideProp"/>
|
||||
</el-card>
|
||||
<el-card v-if="showProp" :key="nodePropKey" class="card-prop">
|
||||
<template #header>节点属性</template>
|
||||
<div>
|
||||
节点ID:{{nodeData.properties.node }}
|
||||
</div>
|
||||
<div>
|
||||
节点名称:{{nodeData.text.value }}
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import LogicFlow from '@logicflow/core';
|
||||
// 引入整体背景的样式
|
||||
import '@logicflow/core/dist/style/index.css';
|
||||
import { Menu } from "@logicflow/extension";
|
||||
import AiNodeExtension from '@/components/flow/index'
|
||||
import RegisteMenu from '@/components/flow/menu.js'
|
||||
import NodePanel from './nodePanel.vue'
|
||||
const themeApprove = {
|
||||
rect: { // 矩形样式
|
||||
radius: 8,
|
||||
stroke: '#3CB371'
|
||||
},
|
||||
circle: {
|
||||
r: 25,
|
||||
stroke: '#FF6347'
|
||||
},
|
||||
polygon: {
|
||||
stroke: '#6495ED',
|
||||
},
|
||||
polyline: {
|
||||
strokeWidth: 1,
|
||||
stroke: 'red'
|
||||
},
|
||||
edgeText: {
|
||||
background: {
|
||||
fill: 'white',
|
||||
},
|
||||
},
|
||||
}
|
||||
let showProp=ref(false)
|
||||
let nodeData=reactive(null)
|
||||
const nodePanel=ref()
|
||||
const config = {
|
||||
stopScrollGraph: true,
|
||||
stopZoomGraph: true,
|
||||
grid: {
|
||||
size: 10,
|
||||
visible: true,
|
||||
type: 'mesh',
|
||||
config: {
|
||||
color: '#DCDCDC',
|
||||
}
|
||||
},
|
||||
keyboard: { enabled: true },
|
||||
style: themeApprove,
|
||||
plugins: [AiNodeExtension,Menu]
|
||||
};
|
||||
const flow = ref()
|
||||
let lf = ref(null)
|
||||
let nodePropKey=ref(1)
|
||||
const hideProp=(e)=>{
|
||||
if(e.target.classList.contains("lf-drag-able")){
|
||||
showProp.value=false
|
||||
}
|
||||
}
|
||||
const initEvent=(lf)=>{
|
||||
lf.on("element:click",node=>{
|
||||
nodeData=node.data
|
||||
showProp.value=true
|
||||
nodePropKey.value++
|
||||
console.log("-->",nodeData)
|
||||
});
|
||||
lf.on("node:dnd-add",data=>{
|
||||
nodeData=data.data;
|
||||
showProp.value=true
|
||||
nodePropKey.value++
|
||||
doUpdateState()
|
||||
});
|
||||
lf.on("node:delete",data=>{
|
||||
if(data.data.text.value=="目标绘图"){
|
||||
ElMessage.error("目标绘图节点不能删除");
|
||||
setTimeout(() => {
|
||||
lf.undo();
|
||||
}, 400);
|
||||
return;
|
||||
}
|
||||
doUpdateState()
|
||||
});
|
||||
lf.on("node:contextmenu",(d,e,p)=>{
|
||||
if(d.data.text.value=="目标绘图"){
|
||||
setTimeout(()=>{
|
||||
document.querySelector(".lf-menu").style.display="none";
|
||||
},0)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const doUpdateState=()=>{
|
||||
nodePanel.value.updateNode(lf.value.getGraphData());
|
||||
}
|
||||
onMounted(() => {
|
||||
const logicFlow = new LogicFlow({
|
||||
...config,
|
||||
container: flow.value
|
||||
})
|
||||
lf.value = logicFlow
|
||||
RegisteMenu(logicFlow)
|
||||
initEvent(logicFlow);
|
||||
window.lf=lf
|
||||
logicFlow.render({
|
||||
nodes: [
|
||||
{
|
||||
id: 'node_1',
|
||||
type: 'ai-node',
|
||||
x: 150,
|
||||
y: 20,
|
||||
fill:'#409effaa',
|
||||
text: '图像缩放',
|
||||
properties:{
|
||||
node:201
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'node_2',
|
||||
type: 'ai-node',
|
||||
x: 150,
|
||||
y: 80,
|
||||
fill:'#50e904',
|
||||
text: '目标绘图',
|
||||
properties:{
|
||||
node:900
|
||||
}
|
||||
}
|
||||
],
|
||||
edges: [
|
||||
|
||||
]
|
||||
})
|
||||
doUpdateState();
|
||||
});
|
||||
</script>
|
||||
<style lang='scss'>
|
||||
.flow-demo1 {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding:0px 12px;
|
||||
.viewport {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.custom-anchor {
|
||||
stroke: #999;
|
||||
stroke-width: 1;
|
||||
fill: #d9d9d9;
|
||||
cursor: crosshair;
|
||||
rx: 3;
|
||||
ry: 3;
|
||||
}
|
||||
|
||||
.custom-anchor:hover {
|
||||
fill: #ff7f0e;
|
||||
stroke: #ff7f0e;
|
||||
}
|
||||
.flow-card{
|
||||
height: 80%;
|
||||
width:calc(100% - 450px);
|
||||
margin: 0px 12px;
|
||||
.el-card__body{
|
||||
height:100%;
|
||||
padding:4px;
|
||||
}
|
||||
}
|
||||
.node-panel{
|
||||
width:240px;
|
||||
.el-tabs__item{
|
||||
padding: 0px 10px !important;
|
||||
}
|
||||
}
|
||||
.card-prop{
|
||||
height: 300px;
|
||||
width:200px;
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,87 +0,0 @@
|
|||
<template>
|
||||
<div class="node-panel">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="前处理算子">
|
||||
<div v-for="(it1, idx1) in list1" :key="idx1" class="div-item" @mousedown="dragNode(it1, 1)" v-show="it1.show">
|
||||
{{ it1.text }}
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="后处理算子">
|
||||
<div v-for="(it2, idx2) in list2" :key="idx2" class="div-item item2" @mousedown="dragNode(it2, 2)" v-show="it2.show">
|
||||
{{ it2.text }}
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
lf: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
const dragNode = (it, t) => {
|
||||
props.lf.dnd.startDrag({
|
||||
type: 'ai-node',
|
||||
text: it.text,
|
||||
fill: t == 1 ? '#409effaa' : '#ccccccaa',
|
||||
properties:{
|
||||
node:it.id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const list1 = reactive([
|
||||
{ text: "图像缩放", id: 201,show:true },
|
||||
{ text: "RGB12图像格式转换", id: 202,show:true },
|
||||
{ text: "RGB24图像格式转换", id: 203,show:true },
|
||||
{ text: "RGB36图像格式转换", id: 204,show:true },
|
||||
{ text: "RGB48图像格式转换", id: 205,show:true },
|
||||
{ text: "RGB72图像格式转换", id: 206,show:true }
|
||||
])
|
||||
|
||||
const list2 = reactive([
|
||||
{ text: "VIT推理算子1", id: 301,show:true },
|
||||
{ text: "VIT推理算子2", id: 302,show:true },
|
||||
{ text: "VIT后处理算子1", id: 303,show:true },
|
||||
{ text: "VIT后处理算子2", id: 304,show:true },
|
||||
{ text: "VIT后处理算子3", id: 305,show:true },
|
||||
]);
|
||||
|
||||
const updateNode=(nodes)=>{
|
||||
let nds=nodes.nodes.map(d=>d.properties.node);
|
||||
list2.forEach(d=>{
|
||||
d.show=nds.indexOf(d.id)==-1
|
||||
})
|
||||
list1.forEach(d=>{
|
||||
d.show=nds.indexOf(d.id)==-1
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
updateNode
|
||||
})
|
||||
|
||||
</script>
|
||||
<style lang='scss'>
|
||||
.node-panel {
|
||||
.div-item {
|
||||
font-size: 12px;
|
||||
border: solid 1px #888;
|
||||
margin-bottom: 10px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
background: #409effaa;
|
||||
user-select: none;
|
||||
cursor: move;
|
||||
|
||||
&.item2 {
|
||||
background: #ccccccaa;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,25 +0,0 @@
|
|||
<template>
|
||||
<div class="split-split1-index">
|
||||
<div style="text-align: center;">
|
||||
<svg-icon icon-class="build" style="width:100px;height:100px;" />
|
||||
</div>
|
||||
<div style="text-align: center;">
|
||||
建设中。。。。。
|
||||
</div>
|
||||
<iframe :src="url" style="width:100%;height:100%;position: absolute;top:0px;"></iframe>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
let url=ref("")
|
||||
onMounted(()=>{
|
||||
url.value="./onnx/onnx.html?url=/ai/siamRPN_192.onnx"
|
||||
});
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
.split-split1-index{
|
||||
position: relative;
|
||||
padding: 12px 24px;
|
||||
height:100%;
|
||||
}
|
||||
</style>
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue