feat: 优化个人页面
parent
414ee924b9
commit
66ea7f5436
2
.env
2
.env
|
|
@ -2,7 +2,7 @@
|
|||
# 应用配置
|
||||
# =====================================================================================
|
||||
# 网站标题
|
||||
VITE_TITLE = 绝弹管理系统
|
||||
VITE_TITLE = 绝弹管理后台
|
||||
# 网站副标题
|
||||
VITE_SUBTITLE = 快速开发web应用的模板工具
|
||||
# API接口前缀:参见 axios 的 baseURL
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { modal } from "@/utils/modal";
|
||||
import { Doption, Dropdown, Link, Message, TableColumnData } from "@arco-design/web-vue";
|
||||
import { isArray, merge } from "lodash-es";
|
||||
import { reactive } from "vue";
|
||||
|
|
@ -5,7 +6,6 @@ import { useFormModal } from "../form";
|
|||
import { TableInstance } from "./table";
|
||||
import { config } from "./table.config";
|
||||
import { UseTableOptions } from "./use-interface";
|
||||
import { modal } from "@/utils/modal";
|
||||
|
||||
const onClick = async (item: any, columnData: any, getTable: any) => {
|
||||
if (item.type === "modify") {
|
||||
|
|
@ -128,17 +128,21 @@ export const useTable = (optionsOrFn: UseTableOptions | (() => UseTableOptions))
|
|||
);
|
||||
});
|
||||
const trigger = () => (
|
||||
<span class="inline-flex p-1 hover:bg-slate-200 rounded cursor-pointer">
|
||||
<span class="px-2 py-[1px] h-6 vertical-b rounded cursor-pointer text-[rgb(var(--link-6))] hover:bg-[var(--color-fill-2)]">
|
||||
<i class="icon-park-outline-more"></i>
|
||||
</span>
|
||||
);
|
||||
return (
|
||||
<Dropdown position="br">
|
||||
{{
|
||||
default: trigger,
|
||||
content: content,
|
||||
}}
|
||||
</Dropdown>
|
||||
<>
|
||||
<Link>编辑</Link>
|
||||
<Link>详情</Link>
|
||||
<Dropdown position="br">
|
||||
{{
|
||||
default: trigger,
|
||||
content: content,
|
||||
}}
|
||||
</Dropdown>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,68 @@
|
|||
<template>
|
||||
<bread-page class="">Demo Page</bread-page>
|
||||
<bread-page class="">
|
||||
<div v-for="menu in state.menus" :key="menu.id" class="mt-8">
|
||||
<div class="flex justify-between pb-1.5 border-b">
|
||||
<a-checkbox v-model="menu.checked" :indeterminate="indeter(menu.children)">
|
||||
<span class="font-semibold">
|
||||
{{ menu.title }}
|
||||
</span>
|
||||
</a-checkbox>
|
||||
<a-link> 设置权限 </a-link>
|
||||
</div>
|
||||
<div class="flex gap-4 mt-4">
|
||||
<template v-if="menu.children">
|
||||
<a-checkbox
|
||||
v-model="item.checked"
|
||||
@change="onItemChange(item, menu)"
|
||||
v-for="item in menu.children || []"
|
||||
:key="item.id"
|
||||
>
|
||||
{{ item.title }}
|
||||
</a-checkbox>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="text-gray-400">暂无子项</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</bread-page>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import { menus } from "@/router";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
|
||||
const items = cloneDeep(menus) as any;
|
||||
for (const item of items) {
|
||||
item.checked = false;
|
||||
if (item.children) {
|
||||
for (const child of item.children) {
|
||||
child.checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const state = reactive({
|
||||
menus: items,
|
||||
});
|
||||
|
||||
const indeter = (items: any[]) => {
|
||||
if (!items) {
|
||||
return false;
|
||||
}
|
||||
const checked = items.filter((item) => item.checked);
|
||||
return checked.length > 0 && checked.length < items.length;
|
||||
};
|
||||
|
||||
const onItemChange = (item: any, menu: any) => {
|
||||
const checked = menu.children.filter((item: any) => item.checked);
|
||||
if (checked === 0) {
|
||||
menu.checked = false;
|
||||
} else if (checked === menu.children.length) {
|
||||
menu.checked = true;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,23 @@
|
|||
<template>
|
||||
<bread-page id="list-page">
|
||||
<template #default>
|
||||
<div>
|
||||
<div class="flex justify-between items-center gap-4">
|
||||
<div class="flex justify-between gap-4">
|
||||
<div class="">
|
||||
<span class="text-base font-semibold text-gray-900">媒体素材</span>
|
||||
<div class="mt-1 text-gray-400">
|
||||
用户上传的图片、视频、音频等素材,可用于文章、图文、视频等内容的编辑。
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-gray-400">
|
||||
<div>
|
||||
<a-button type="primary">
|
||||
<template #icon>
|
||||
<i class="icon-park-outline-plus"></i>
|
||||
</template>
|
||||
添加</a-button>
|
||||
添加
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-gray-400">
|
||||
用户上传的图片、视频、音频等素材,可用于文章、图文、视频等内容的编辑。
|
||||
</div>
|
||||
</div>
|
||||
<AList class="mt-4 bg-white" :bordered="true">
|
||||
<template #header>
|
||||
|
|
@ -105,8 +108,7 @@
|
|||
<AListItemMeta title="测试图片.png" description="image/png 1.2MB">
|
||||
<template #avatar>
|
||||
<ACheckbox class="mr-3"></ACheckbox>
|
||||
<AImage src="https://picsum.photos/seed/picsum/200/300" height="40">
|
||||
<img src="https://picsum.photos/seed/picsum/200/300" alt="" />
|
||||
<AImage src="https://picsum.photos/seed/picsum/200/300?12" height="32" width="48">
|
||||
</AImage>
|
||||
</template>
|
||||
<template #title>
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@
|
|||
<template #content>
|
||||
<section class="my-page m-5 bg-white p-4">
|
||||
<div>
|
||||
<div class="font-semibold text-lg flex items-center">个人设置</div>
|
||||
<div class="mt-1 text-sm text-gray-400">此表情符号和消息会显示在您的个人资料和界面中。</div>
|
||||
<div class="font-semibold text-base flex items-center">个人设置</div>
|
||||
<div class="text-sm text-gray-400">此表情符号和消息会显示在您的个人资料和界面中。</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="md:flex md:gap-4 mt-3 border-t pt-6">
|
||||
<div class="md:w-56 text-gray-400">基本信息</div>
|
||||
<div class="flex-1 flex">
|
||||
<a-form layout="vertical">
|
||||
<a-form :model="user" layout="vertical">
|
||||
<a-form-item label="个人头像">
|
||||
<a-avatar :size="64">
|
||||
<img src="https://github.com/juetan.png" alt="" />
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<template #help> 用作系统内显示的名称,可在后台修改 </template>
|
||||
</a-form-item>
|
||||
<a-form-item label="个人描述">
|
||||
<a-textarea v-model="user.description" placeholder="请输入" class="!w-[432px]"></a-textarea>
|
||||
<a-textarea v-model="user.description" placeholder="请输入" class="!w-[580px] h-24"></a-textarea>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
<div class="md:flex md:gap-4 mt-6 pt-6 border-t">
|
||||
<div class="md:w-56 text-gray-400">联系方式</div>
|
||||
<div class="flex-1">
|
||||
<a-form layout="vertical">
|
||||
<a-form :model="user" layout="vertical">
|
||||
<a-form-item label="消息推送">
|
||||
<div>
|
||||
<a-checkbox-group direction="vertical" v-model="user.msg">
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
<div class="md:flex md:gap-4 mt-6 pt-6 border-t">
|
||||
<div class="md:w-56 text-gray-400">偏好设置</div>
|
||||
<div class="flex-1">
|
||||
<a-form layout="vertical">
|
||||
<a-form :model="user" layout="vertical">
|
||||
<a-form-item label="主题">
|
||||
<div>
|
||||
<a-radio-group v-model="user.theme" direction="vertical">
|
||||
|
|
@ -72,6 +72,35 @@
|
|||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:flex md:gap-4 mt-6 pt-6 border-t">
|
||||
<div class="md:w-56 text-gray-400">
|
||||
其他功能
|
||||
</div>
|
||||
<div class="flex-1 grid">
|
||||
<div class="mb-3">功能列表</div>
|
||||
<div v-for="i in 3" class="border-t py-4 flex justify-between items-center gap-4">
|
||||
<div class="flex gap-3 items-center">
|
||||
<div class="p-2 bg-slate-100 rounded">
|
||||
<svg t="1692015760052" class="icon h-8 w-10" viewBox="0 0 1264 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7353" width="200" height="200"><path d="M0 333.884235a90.352941 90.352941 0 0 1 90.352941-90.352941h1084.235294a90.352941 90.352941 0 0 1 90.352941 90.352941v271.058824h-256a105.411765 105.411765 0 1 0 0 210.823529H1264.941176v90.352941a90.352941 90.352941 0 0 1-90.352941 90.352942H90.352941a90.352941 90.352941 0 0 1-90.352941-90.352942v-572.235294z m1008.941176 421.647059a45.176471 45.176471 0 1 0 0-90.352941 45.176471 45.176471 0 0 0 0 90.352941z" fill="#C1D0FF" p-id="7354"></path><path d="M90.352941 190.343529a60.235294 60.235294 0 0 1 66.861177-59.843764l963.764706 107.068235A60.235294 60.235294 0 0 1 1174.588235 297.441882v187.030589a60.235294 60.235294 0 0 1-60.235294 60.235294H150.588235a60.235294 60.235294 0 0 1-60.235294-60.235294V190.343529zM140.649412 83.275294A90.352941 90.352941 0 0 1 249.615059 13.251765l886.573176 205.914353L139.264 90.051765l1.385412-6.746353z" fill="#0B77FF" p-id="7355"></path><path d="M0 331.294118a90.352941 90.352941 0 0 1 90.352941-90.352942h1084.235294a90.352941 90.352941 0 0 1 90.352941 90.352942v271.058823h-256a105.411765 105.411765 0 1 0 0 210.82353H1264.941176v90.352941a90.352941 90.352941 0 0 1-90.352941 90.352941H90.352941a90.352941 90.352941 0 0 1-90.352941-90.352941V331.294118z" fill="#E8E8E8" fill-opacity=".1" p-id="7356"></path><path d="M90.352941 271.058824h1084.235294a60.235294 60.235294 0 0 1 60.235294 60.235294v240.941176h-225.882353a135.529412 135.529412 0 1 0 0 271.058824H1234.823529v60.235294a60.235294 60.235294 0 0 1-60.235294 60.235294H90.352941a60.235294 60.235294 0 0 1-60.235294-60.235294V331.294118a60.235294 60.235294 0 0 1 60.235294-60.235294z m1174.588235 60.235294a90.352941 90.352941 0 0 0-90.352941-90.352942H90.352941a90.352941 90.352941 0 0 0-90.352941 90.352942v572.235294a90.352941 90.352941 0 0 0 90.352941 90.352941h1084.235294a90.352941 90.352941 0 0 0 90.352941-90.352941v-90.352941h-256a105.411765 105.411765 0 1 1 0-210.82353H1264.941176v-271.058823z" fill="#FFFFFF" fill-opacity=".6" p-id="7357"></path><path d="M353.882353 424.237176H271.058824l82.823529 195.764706h-41.411765v39.152942h82.82353v39.152941h-82.82353v39.152941h82.82353v78.305882h82.823529v-78.305882h82.823529v-39.152941h-82.823529v-39.152941h82.823529v-39.152942H519.529412l82.823529-195.764706h-82.823529l-82.82353 195.764706-82.823529-195.764706z" fill="#FFFFFF" p-id="7358"></path></svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-900">支付功能</div>
|
||||
<div class="text-gray-400 mt-1">通知管理员由企业互联的管理员来设置,拥有通知业务的最大权限。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a-switch checked-color="#3c9">
|
||||
<template #checked>
|
||||
已启用
|
||||
</template>
|
||||
<template #unchecked>
|
||||
未启用
|
||||
</template>
|
||||
</a-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:flex md:gap-4 mt-6 pt-6 border-t">
|
||||
<div class="md:w-56 text-gray-400"></div>
|
||||
<div class="flex-1">
|
||||
|
|
@ -108,8 +137,8 @@ const user =reactive({
|
|||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.my-page :deep {
|
||||
<style lang="less">
|
||||
.my-page {
|
||||
.arco-form-item.arco-form-item-error,
|
||||
.arco-form-item.arco-form-item-has-help {
|
||||
margin-bottom: 20px;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ const table = useTable({
|
|||
{
|
||||
title: "操作",
|
||||
type: "dropdown",
|
||||
width: 60,
|
||||
align: "center",
|
||||
width: 140,
|
||||
dropdowns: [
|
||||
{
|
||||
type: "modify",
|
||||
|
|
|
|||
|
|
@ -146,13 +146,8 @@ const table = useTable({
|
|||
<route lang="json">
|
||||
{
|
||||
"meta": {
|
||||
"sort": 10301,
|
||||
"title": "用户管理",
|
||||
"icon": "icon-park-outline-user"
|
||||
},
|
||||
"parentMeta": {
|
||||
"title": "系统管理",
|
||||
"icon": "icon-park-outline-setting",
|
||||
"icon": "icon-park-outline-config",
|
||||
"sort": 20000
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
<template>
|
||||
<BreadPage>
|
||||
<template #content>
|
||||
<a-tabs default-active-key="1" size="large" class="bg-white m-4">
|
||||
<a-tab-pane key="1" title="全部">
|
||||
<Table v-bind="table" class="px-4 pb-4"></Table>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" title="已通过(12)"></a-tab-pane>
|
||||
</a-tabs>
|
||||
</template>
|
||||
</BreadPage>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { api } from "@/api";
|
||||
import { Table, useTable } from "@/components";
|
||||
import { dayjs } from "@/plugins";
|
||||
import { Avatar, Button } from "@arco-design/web-vue";
|
||||
|
||||
const table = useTable({
|
||||
data: async (model, paging) => {
|
||||
return api.user.getUsers({ ...model, ...paging });
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
type: "index",
|
||||
},
|
||||
{
|
||||
title: "用户昵称",
|
||||
dataIndex: "username",
|
||||
width: 200,
|
||||
render: ({ record }) => (
|
||||
<div class="flex items-center">
|
||||
<Avatar size={32}>
|
||||
<img src={record.avatar} alt="" />
|
||||
</Avatar>
|
||||
<span class="ml-2 flex-1 flex flex-col overflow-hidden">
|
||||
<span>{record.nickname}</span>
|
||||
<span class="text-gray-400 text-xs truncate">账号:{record.username}</span>
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "用户描述",
|
||||
dataIndex: "description",
|
||||
},
|
||||
{
|
||||
title: "用户邮箱",
|
||||
dataIndex: "email",
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "createdAt",
|
||||
width: 200,
|
||||
render: ({ record }) => dayjs(record.createdAt).format(),
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
type: "button",
|
||||
width: 148,
|
||||
buttons: [
|
||||
{
|
||||
type: "modify",
|
||||
text: "修改",
|
||||
},
|
||||
{
|
||||
type: "delete",
|
||||
text: "删除",
|
||||
onClick: async ({ record }) => {
|
||||
return api.user.delUser(record.id, { toast: true });
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
search: {
|
||||
items: [
|
||||
{
|
||||
extend: "nickname",
|
||||
required: false,
|
||||
itemProps: {
|
||||
hideLabel: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
create: {
|
||||
title: "新建用户",
|
||||
trigger: () => (
|
||||
<Button type="primary">
|
||||
{{
|
||||
icon: () => <i class="icon-park-outline-people-plus-one" />,
|
||||
default: () => "添加",
|
||||
}}
|
||||
</Button>
|
||||
),
|
||||
modalProps: {
|
||||
width: 772,
|
||||
maskClosable: false,
|
||||
},
|
||||
formProps: {
|
||||
layout: "vertical",
|
||||
class: "!grid grid-cols-2 gap-x-3",
|
||||
},
|
||||
items: [
|
||||
{
|
||||
field: "username",
|
||||
label: "登录账号",
|
||||
type: "input",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: "nickname",
|
||||
label: "用户昵称",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
field: "description",
|
||||
label: "个人描述",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
field: "password",
|
||||
label: "密码",
|
||||
type: "password",
|
||||
},
|
||||
{
|
||||
label: "头像",
|
||||
field: "avatar",
|
||||
type: "select",
|
||||
},
|
||||
{
|
||||
field: "[startTime,endTime]",
|
||||
label: "日期范围",
|
||||
type: "dateRange",
|
||||
nodeProps: {},
|
||||
},
|
||||
],
|
||||
submit: ({ model }) => {
|
||||
return api.user.addUser(model);
|
||||
},
|
||||
},
|
||||
modify: {
|
||||
extend: true,
|
||||
title: "修改用户",
|
||||
submit: ({ model }) => {
|
||||
return api.user.updateUser(model.id, model);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
<route lang="json">
|
||||
{
|
||||
"meta": {
|
||||
"sort": 10301,
|
||||
"title": "用户管理",
|
||||
"icon": "icon-park-outline-user"
|
||||
}
|
||||
}
|
||||
</route>
|
||||
|
|
@ -11,20 +11,18 @@ declare module '@vue/runtime-core' {
|
|||
ABreadcrumb: typeof import('@arco-design/web-vue')['Breadcrumb']
|
||||
ABreadcrumbItem: typeof import('@arco-design/web-vue')['BreadcrumbItem']
|
||||
AButton: typeof import('@arco-design/web-vue')['Button']
|
||||
ACard: typeof import('@arco-design/web-vue')['Card']
|
||||
ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
|
||||
ACheckboxGroup: typeof import('@arco-design/web-vue')['CheckboxGroup']
|
||||
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider']
|
||||
ADoption: typeof import('@arco-design/web-vue')['Doption']
|
||||
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
|
||||
ADropdown: typeof import('@arco-design/web-vue')['Dropdown']
|
||||
AEmpty: typeof import('@arco-design/web-vue')['Empty']
|
||||
AForm: typeof import('@arco-design/web-vue')['Form']
|
||||
AFormItem: typeof import('@arco-design/web-vue')['FormItem']
|
||||
AImage: typeof import('@arco-design/web-vue')['Image']
|
||||
AInput: typeof import('@arco-design/web-vue')['Input']
|
||||
AInputGroup: typeof import('@arco-design/web-vue')['InputGroup']
|
||||
AInputPassword: typeof import('@arco-design/web-vue')['InputPassword']
|
||||
AInputSearch: typeof import('@arco-design/web-vue')['InputSearch']
|
||||
ALayout: typeof import('@arco-design/web-vue')['Layout']
|
||||
ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent']
|
||||
ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader']
|
||||
|
|
@ -38,9 +36,11 @@ declare module '@vue/runtime-core' {
|
|||
APagination: typeof import('@arco-design/web-vue')['Pagination']
|
||||
ARadio: typeof import('@arco-design/web-vue')['Radio']
|
||||
ARadioGroup: typeof import('@arco-design/web-vue')['RadioGroup']
|
||||
ASelect: typeof import('@arco-design/web-vue')['Select']
|
||||
ASpace: typeof import('@arco-design/web-vue')['Space']
|
||||
ASubMenu: typeof import('@arco-design/web-vue')['SubMenu']
|
||||
ASwitch: typeof import('@arco-design/web-vue')['Switch']
|
||||
ATabPane: typeof import('@arco-design/web-vue')['TabPane']
|
||||
ATabs: typeof import('@arco-design/web-vue')['Tabs']
|
||||
ATag: typeof import('@arco-design/web-vue')['Tag']
|
||||
ATextarea: typeof import('@arco-design/web-vue')['Textarea']
|
||||
ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
|
||||
|
|
|
|||
Loading…
Reference in New Issue