From d5e314e7cedfd488dd5a314536b7ff127ae826cf Mon Sep 17 00:00:00 2001 From: pdsuwwz Date: Wed, 28 Jun 2023 18:34:57 +0800 Subject: [PATCH 1/2] feat: avatar member field --- components.d.ts | 1 + src/assets/images/member-avatar.png | Bin 0 -> 10535 bytes src/modules/MemberTeam/data/index.ts | 4 +++ src/modules/MemberTeam/pages/preview.vue | 40 ++++++++++++++--------- 4 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 src/assets/images/member-avatar.png diff --git a/components.d.ts b/components.d.ts index 97d0e17..78f29a2 100644 --- a/components.d.ts +++ b/components.d.ts @@ -34,6 +34,7 @@ declare module 'vue' { NDropdown: typeof import('naive-ui')['NDropdown'] NForm: typeof import('naive-ui')['NForm'] NFormItem: typeof import('naive-ui')['NFormItem'] + NFormItemGi: typeof import('naive-ui')['NFormItemGi'] NGi: typeof import('naive-ui')['NGi'] NGrid: typeof import('naive-ui')['NGrid'] NIcon: typeof import('naive-ui')['NIcon'] diff --git a/src/assets/images/member-avatar.png b/src/assets/images/member-avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..49500932f03540d64c2026099c356c7463d8c18a GIT binary patch literal 10535 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 L)4{ULoDuhbrqxSB literal 0 HcmV?d00001 diff --git a/src/modules/MemberTeam/data/index.ts b/src/modules/MemberTeam/data/index.ts index 0d851f1..2e11599 100644 --- a/src/modules/MemberTeam/data/index.ts +++ b/src/modules/MemberTeam/data/index.ts @@ -4,6 +4,8 @@ import { PresenceBlocked10Regular } from '@vicons/fluent' +import memberAvatar from '@/assets/images/member-avatar.png' + // 随机获取数组中某一项 function getRandomValueFromArray(arr: Array): T { const randomIndex = Math.floor(Math.random() * arr.length) @@ -108,6 +110,7 @@ export interface TypeMemberPerson { username: string roleId: string userId: string + avatar: string email: string phone: string rank: string @@ -132,6 +135,7 @@ export const memberTeamList = Array.from({ length: 100 }).map((_, index) => { roleId: roleItem.value, rank: rankItem.value, phone: 10000000000 + _index + '', + avatar: memberAvatar, email: `${userId}@admin.com`, memberStatus: Math.random() > 0.5 ? 0 : 1 } as TypeMemberPerson diff --git a/src/modules/MemberTeam/pages/preview.vue b/src/modules/MemberTeam/pages/preview.vue index 20eb9ad..b20a9d1 100644 --- a/src/modules/MemberTeam/pages/preview.vue +++ b/src/modules/MemberTeam/pages/preview.vue @@ -3,6 +3,7 @@ - - - - - + + + + + + ({ username: '', roleId: '', userId: '', + avatar: '', email: '', rank: '', phone: '', From 29745a47a6799e96beaf501f48b5a8b3f5815ac3 Mon Sep 17 00:00:00 2001 From: pdsuwwz Date: Thu, 29 Jun 2023 16:18:16 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=91=20feat:=20avatar=20upload=20co?= =?UTF-8?q?mponent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc-auto-import-costom.json | 1 + components.d.ts | 2 + .../MemberTeam/components/AvatarUpload.vue | 147 ++++++++++++++++++ src/modules/MemberTeam/pages/index.vue | 16 +- src/modules/MemberTeam/pages/preview.vue | 69 +++++--- src/utils/fileHandler.ts | 38 +++++ vite.config.ts | 7 +- 7 files changed, 250 insertions(+), 30 deletions(-) create mode 100644 src/modules/MemberTeam/components/AvatarUpload.vue create mode 100644 src/utils/fileHandler.ts diff --git a/.eslintrc-auto-import-costom.json b/.eslintrc-auto-import-costom.json index af7cf41..0a5939b 100644 --- a/.eslintrc-auto-import-costom.json +++ b/.eslintrc-auto-import-costom.json @@ -1,5 +1,6 @@ { "globals": { + "defineModel": true, "PropsOptionsMixed": true } } diff --git a/components.d.ts b/components.d.ts index 78f29a2..1317d27 100644 --- a/components.d.ts +++ b/components.d.ts @@ -9,6 +9,7 @@ declare module 'vue' { export interface GlobalComponents { 404: typeof import('./src/components/404.vue')['default'] Avatar: typeof import('./src/components/Navigation/Avatar.vue')['default'] + AvatarUpload: typeof import('./src/components/AvatarUpload/index.vue')['default'] ChangeTheme: typeof import('./src/components/Navigation/ChangeTheme.vue')['default'] Footer: typeof import('./src/components/Footer/index.vue')['default'] FullScreen: typeof import('./src/components/Navigation/FullScreen.vue')['default'] @@ -37,6 +38,7 @@ declare module 'vue' { NFormItemGi: typeof import('naive-ui')['NFormItemGi'] NGi: typeof import('naive-ui')['NGi'] NGrid: typeof import('naive-ui')['NGrid'] + NGridItem: typeof import('naive-ui')['NGridItem'] NIcon: typeof import('naive-ui')['NIcon'] NInput: typeof import('naive-ui')['NInput'] NList: typeof import('naive-ui')['NList'] diff --git a/src/modules/MemberTeam/components/AvatarUpload.vue b/src/modules/MemberTeam/components/AvatarUpload.vue new file mode 100644 index 0000000..26d241f --- /dev/null +++ b/src/modules/MemberTeam/components/AvatarUpload.vue @@ -0,0 +1,147 @@ + + + + + + diff --git a/src/modules/MemberTeam/pages/index.vue b/src/modules/MemberTeam/pages/index.vue index 0c13d4a..739245e 100755 --- a/src/modules/MemberTeam/pages/index.vue +++ b/src/modules/MemberTeam/pages/index.vue @@ -131,6 +131,15 @@ const renderIcon = (icon: Component, className = '') => { } +const goToMemberTeamPreview = (row: TypeMemberPerson) => { + router.push({ + name: 'MemberTeamPreview', + params: { + datasetId: row.userId + } + }, `成员查看-${row.username}`) +} + const createActionsColumns = (row: TypeMemberPerson) => { return h( NDropdown, @@ -142,12 +151,7 @@ const createActionsColumns = (row: TypeMemberPerson) => { icon: renderIcon(IconNotepadPerson24Regular), props: { onClick: () => { - router.push({ - name: 'MemberTeamPreview', - params: { - datasetId: row.userId - } - }, `成员查看-${row.username}`) + goToMemberTeamPreview(row) } } }, diff --git a/src/modules/MemberTeam/pages/preview.vue b/src/modules/MemberTeam/pages/preview.vue index b20a9d1..1f266ff 100644 --- a/src/modules/MemberTeam/pages/preview.vue +++ b/src/modules/MemberTeam/pages/preview.vue @@ -11,32 +11,51 @@ :model="memberFormModel" label-placement="top" label-width="auto" - disabled + :disabled="disabledForm" > - - - - - + + + + + + + + + + + + + + - + +