mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-11-15 21:53:48 +08:00
版本预发布
This commit is contained in:
206
web/src/views/home/account/BasicSetting.vue
Normal file
206
web/src/views/home/account/BasicSetting.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-card
|
||||
v-show="showInfo"
|
||||
title="😋 个人信息"
|
||||
embedded
|
||||
:bordered="false"
|
||||
closable
|
||||
hoverable
|
||||
@close="handleClose"
|
||||
>
|
||||
<n-row>
|
||||
<n-thing content-indented>
|
||||
<template #header>
|
||||
{{ timeFix() }},{{ formValue.realName }},今天又是充满活力的一天!
|
||||
</template>
|
||||
<template #header-extra> </template>
|
||||
<template #description>
|
||||
<n-descriptions
|
||||
label-placement="left"
|
||||
style="margin-top: 15px"
|
||||
column="2"
|
||||
content-style="padding-right: 20px;"
|
||||
>
|
||||
<n-descriptions-item label="用户ID">{{ formValue.id }}</n-descriptions-item>
|
||||
<n-descriptions-item label="用户名"> {{ formValue.username }} </n-descriptions-item>
|
||||
<n-descriptions-item label="登录IP">{{
|
||||
formValue.lastLoginIp
|
||||
}}</n-descriptions-item>
|
||||
<n-descriptions-item label="登录时间"
|
||||
>{{ formValue.lastLoginAt }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="累计登录">
|
||||
{{ formValue.loginCount }} 次</n-descriptions-item
|
||||
>
|
||||
<n-descriptions-item label="注册时间">
|
||||
{{ formValue.createdAt }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="所属部门">
|
||||
<n-tag size="small" type="success" strong round :bordered="false">
|
||||
{{ formValue.deptName }}
|
||||
<template #icon>
|
||||
<n-icon :component="CheckmarkCircle" />
|
||||
</template>
|
||||
</n-tag>
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="所属角色">
|
||||
<n-tag size="small" type="success" strong round :bordered="false">
|
||||
{{ formValue.roleName }}
|
||||
<template #icon>
|
||||
<n-icon :component="CheckmarkCircle" />
|
||||
</template>
|
||||
</n-tag>
|
||||
</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</template>
|
||||
</n-thing>
|
||||
</n-row>
|
||||
</n-card>
|
||||
|
||||
<n-form
|
||||
:label-width="80"
|
||||
:model="formValue"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
style="margin-top: 15px"
|
||||
>
|
||||
<n-form-item label="头像" path="avatar">
|
||||
<UploadImage :maxNumber="1" v-model:value="formValue.avatar" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="姓名" path="realName">
|
||||
<n-input v-model:value="formValue.realName" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="QQ号码" path="qq">
|
||||
<n-input v-model:value="formValue.qq" placeholder="请输入QQ号码" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="生日" path="birthday">
|
||||
<DatePicker v-model:formValue="formValue.birthday" type="date" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="性别" path="sex">
|
||||
<n-radio-group v-model:value="formValue.sex" name="sex">
|
||||
<n-space>
|
||||
<n-radio :value="1">男</n-radio>
|
||||
<n-radio :value="2">女</n-radio>
|
||||
<n-radio :value="3">保密</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="所在省市区" path="cityId">
|
||||
<CitySelector v-model:value="formValue.cityId" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="联系地址" path="address">
|
||||
<n-input type="textarea" v-model:value="formValue.address" placeholder="联系地址" />
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" :loading="formBtnLoading" @click="formSubmit"
|
||||
>保存更新</n-button
|
||||
>
|
||||
<n-button :loading="formBtnLoading" @click="resetForm">重置</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import UploadImage from '@/components/Upload/uploadImage.vue';
|
||||
import CitySelector from '@/components/CitySelector/citySelector.vue';
|
||||
import DatePicker from '@/components/DatePicker/datePicker.vue';
|
||||
import { getUserInfo, updateMemberProfile } from '@/api/system/user';
|
||||
import { CheckmarkCircle } from '@vicons/ionicons5';
|
||||
import { timeFix } from '@/utils/hotgo';
|
||||
import { UserInfoState, useUserStore } from '@/store/modules/user';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const show = ref(false);
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const formBtnLoading = ref(false);
|
||||
|
||||
const rules = {
|
||||
basicName: {
|
||||
required: true,
|
||||
message: '请输入网站名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const formValue = ref<UserInfoState>({
|
||||
id: 0,
|
||||
deptName: '',
|
||||
roleName: '',
|
||||
cityLabel: '',
|
||||
permissions: [],
|
||||
username: '',
|
||||
realName: '',
|
||||
avatar: '',
|
||||
balance: 0,
|
||||
sex: 1,
|
||||
qq: '',
|
||||
email: '',
|
||||
mobile: '',
|
||||
birthday: '',
|
||||
cityId: 0,
|
||||
address: '',
|
||||
cash: {
|
||||
name: '',
|
||||
account: '',
|
||||
payeeCode: '',
|
||||
},
|
||||
createdAt: '',
|
||||
loginCount: 0,
|
||||
lastLoginAt: '',
|
||||
lastLoginIp: '',
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
updateMemberProfile(formValue.value)
|
||||
.then((_res) => {
|
||||
message.success('更新成功');
|
||||
load();
|
||||
userStore.GetInfo();
|
||||
})
|
||||
.finally(() => {
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
load();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load();
|
||||
});
|
||||
|
||||
async function load() {
|
||||
show.value = true;
|
||||
formValue.value = await getUserInfo();
|
||||
show.value = false;
|
||||
}
|
||||
|
||||
const showInfo = ref(true);
|
||||
function handleClose() {
|
||||
showInfo.value = false;
|
||||
}
|
||||
</script>
|
||||
121
web/src/views/home/account/CashSetting.vue
Normal file
121
web/src/views/home/account/CashSetting.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="请稍候...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="支付宝姓名" path="name">
|
||||
<n-input v-model:value="formValue.name" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="支付宝账号" path="account ">
|
||||
<n-input v-model:value="formValue.account" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="支付宝收款码" path="payeeCode">
|
||||
<UploadImage
|
||||
:maxNumber="1"
|
||||
:helpText="'请上传清晰有效的收款码,图片大小不超过2M'"
|
||||
v-model:value="formValue.payeeCode"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="登录密码" path="password">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.password"
|
||||
placeholder="请输入登录密码验证身份"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref, unref } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import UploadImage from '@/components/Upload/uploadImage.vue';
|
||||
import { BasicUpload } from '@/components/Upload';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import { getUserInfo, updateMemberCash } from '@/api/system/user';
|
||||
|
||||
const show = ref(false);
|
||||
const useUserStore = useUserStoreWidthOut();
|
||||
const globSetting = useGlobSetting();
|
||||
const { uploadUrl } = globSetting;
|
||||
const uploadHeaders = reactive({
|
||||
Authorization: useUserStore.token,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
password: {
|
||||
required: true,
|
||||
message: '请输入登录密码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const formValue = ref({
|
||||
password: '',
|
||||
payeeCode: '',
|
||||
account: '',
|
||||
name: '',
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
updateMemberCash({
|
||||
name: formValue.value.name,
|
||||
account: formValue.value.account,
|
||||
payeeCode: formValue.value.payeeCode,
|
||||
password: formValue.value.password,
|
||||
})
|
||||
.then((_res) => {
|
||||
message.success('更新成功');
|
||||
load();
|
||||
})
|
||||
.finally(() => {});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function uploadChange(list: string[]) {
|
||||
// 单图模式,只需要第一个索引
|
||||
if (list.length > 0) {
|
||||
formValue.value.payeeCode = unref(list[0]);
|
||||
} else {
|
||||
formValue.value.payeeCode = unref('');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load();
|
||||
});
|
||||
|
||||
function load() {
|
||||
show.value = true;
|
||||
getUserInfo()
|
||||
.then((res) => {
|
||||
formValue.value = res.cash;
|
||||
formValue.value.password = '';
|
||||
})
|
||||
.finally(() => {
|
||||
show.value = false;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
317
web/src/views/home/account/SafetySetting.vue
Normal file
317
web/src/views/home/account/SafetySetting.vue
Normal file
@@ -0,0 +1,317 @@
|
||||
<template>
|
||||
<n-grid cols="1" responsive="screen" class="-mt-5">
|
||||
<n-grid-item>
|
||||
<n-list>
|
||||
<n-list-item>
|
||||
<template #suffix>
|
||||
<n-button type="primary" text @click="openUpdatePassForm">修改</n-button>
|
||||
</template>
|
||||
<n-thing title="账户密码">
|
||||
<template #description
|
||||
><span class="text-gray-400">绑定手机和邮箱,并设置密码,帐号更安全</span></template
|
||||
>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item>
|
||||
<template #suffix>
|
||||
<n-button type="primary" text @click="openUpdateMobileForm">修改</n-button>
|
||||
</template>
|
||||
<n-thing title="绑定手机">
|
||||
<template #description
|
||||
><span class="text-gray-400"
|
||||
>已绑定手机号:+86{{ userStore.info?.mobile }}</span
|
||||
></template
|
||||
>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
<n-list-item>
|
||||
<template #suffix>
|
||||
<n-button type="primary" text @click="openUpdateEmailForm">修改</n-button>
|
||||
</template>
|
||||
<n-thing title="绑定邮箱">
|
||||
<template #description
|
||||
><span class="text-gray-400">已绑定邮箱:{{ userStore.info?.email }}</span></template
|
||||
>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
title="修改登录密码"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="当前密码" path="oldPassword">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.oldPassword"
|
||||
placeholder="请输入当前密码"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="新密码" path="newPassword">
|
||||
<n-input type="password" v-model:value="formValue.newPassword" placeholder="请输入新密码" />
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space justify="end">
|
||||
<n-button @click="showModal = false">取消</n-button>
|
||||
<n-button type="primary" @click="formSubmit">修改并重新登录</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-modal>
|
||||
|
||||
<n-modal
|
||||
:block-scroll="false"
|
||||
:mask-closable="false"
|
||||
v-model:show="showMobileModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
title="修改手机号"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<n-form :label-width="80" :model="formMobileValue" ref="formMobileRef">
|
||||
<n-form-item label="短信验证码" path="code" v-if="userStore.info?.mobile !== ''">
|
||||
<n-input-group>
|
||||
<n-input v-model:value="formMobileValue.code" placeholder="请输入验证码" />
|
||||
<n-button
|
||||
type="primary"
|
||||
ghost
|
||||
@click="sendMobileCode"
|
||||
:disabled="isCounting"
|
||||
:loading="sendLoading"
|
||||
>
|
||||
{{ sendLabel }}
|
||||
</n-button>
|
||||
</n-input-group>
|
||||
|
||||
<template #feedback> 接收号码:+86{{ userStore.info?.mobile }} </template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="换绑手机号" path="mobile">
|
||||
<n-input v-model:value="formMobileValue.mobile" placeholder="请输入换绑手机号" />
|
||||
</n-form-item>
|
||||
<div>
|
||||
<n-space justify="end">
|
||||
<n-button @click="showMobileModal = false">取消</n-button>
|
||||
<n-button type="primary" :loading="formMobileBtnLoading" @click="formMobileSubmit"
|
||||
>保存更新</n-button
|
||||
>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-modal>
|
||||
|
||||
<n-modal
|
||||
:block-scroll="false"
|
||||
:mask-closable="false"
|
||||
v-model:show="showEmailModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
title="修改邮箱"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<n-form :label-width="80" :model="formEmailValue" ref="formEmailRef">
|
||||
<n-form-item label="邮箱验证码" path="code" v-if="userStore.info?.email !== ''">
|
||||
<n-input-group>
|
||||
<n-input v-model:value="formEmailValue.code" placeholder="请输入验证码" />
|
||||
<n-button
|
||||
type="primary"
|
||||
ghost
|
||||
@click="sendEmailCode"
|
||||
:disabled="isCounting"
|
||||
:loading="sendLoading"
|
||||
>
|
||||
{{ sendLabel }}
|
||||
</n-button>
|
||||
</n-input-group>
|
||||
<template #feedback> 接收邮箱:{{ userStore.info?.email }} </template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="换绑邮箱" path="email">
|
||||
<n-input v-model:value="formEmailValue.email" placeholder="请输入换绑邮箱" />
|
||||
</n-form-item>
|
||||
<div>
|
||||
<n-space justify="end">
|
||||
<n-button @click="showEmailModal = false">取消</n-button>
|
||||
<n-button type="primary" :loading="formEmailBtnLoading" @click="formEmailSubmit"
|
||||
>保存更新</n-button
|
||||
>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useSendCode } from '@/hooks/common';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
import {
|
||||
updateMemberPwd,
|
||||
updateMemberMobile,
|
||||
updateMemberEmail,
|
||||
SendBindEmail,
|
||||
SendBindSms,
|
||||
} from '@/api/system/user';
|
||||
import { TABS_ROUTES } from '@/store/mutation-types';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
const { sendLabel, isCounting, loading: sendLoading, activateSend } = useSendCode();
|
||||
const userStore = useUserStore();
|
||||
const dialogWidth = ref('75%');
|
||||
const rules = {
|
||||
basicName: {
|
||||
required: true,
|
||||
message: '请输入网站名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const showModal = ref(false);
|
||||
const formValue = ref({
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
updateMemberPwd({
|
||||
oldPassword: formValue.value.oldPassword,
|
||||
newPassword: formValue.value.newPassword,
|
||||
})
|
||||
.then((_res) => {
|
||||
message.success('更新成功');
|
||||
|
||||
userStore.logout().then(() => {
|
||||
message.success('成功退出登录');
|
||||
// 移除标签页
|
||||
localStorage.removeItem(TABS_ROUTES);
|
||||
router
|
||||
.replace({
|
||||
name: 'Login',
|
||||
query: {
|
||||
redirect: route.fullPath,
|
||||
},
|
||||
})
|
||||
.finally(() => location.reload());
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
showModal.value = false;
|
||||
});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openUpdatePassForm() {
|
||||
showModal.value = true;
|
||||
formValue.value.newPassword = '';
|
||||
formValue.value.oldPassword = '';
|
||||
}
|
||||
|
||||
const formMobileBtnLoading = ref(false);
|
||||
const formMobileRef: any = ref(null);
|
||||
const showMobileModal = ref(false);
|
||||
const formMobileValue = ref({
|
||||
mobile: '',
|
||||
code: '',
|
||||
});
|
||||
|
||||
function formMobileSubmit() {
|
||||
formMobileRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
formMobileBtnLoading.value = true;
|
||||
updateMemberMobile({
|
||||
mobile: formMobileValue.value.mobile,
|
||||
code: formMobileValue.value.code,
|
||||
})
|
||||
.then((_res) => {
|
||||
message.success('更新成功');
|
||||
showMobileModal.value = false;
|
||||
userStore.GetInfo();
|
||||
})
|
||||
.finally(() => {
|
||||
formMobileBtnLoading.value = false;
|
||||
});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openUpdateMobileForm() {
|
||||
showMobileModal.value = true;
|
||||
formMobileValue.value.mobile = '';
|
||||
formMobileValue.value.code = '';
|
||||
}
|
||||
|
||||
const formEmailBtnLoading = ref(false);
|
||||
const formEmailRef: any = ref(null);
|
||||
const showEmailModal = ref(false);
|
||||
const formEmailValue = ref({
|
||||
email: '',
|
||||
code: '',
|
||||
});
|
||||
|
||||
function formEmailSubmit() {
|
||||
formEmailRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
formEmailBtnLoading.value = true;
|
||||
updateMemberEmail({
|
||||
email: formEmailValue.value.email,
|
||||
code: formEmailValue.value.code,
|
||||
})
|
||||
.then((_res) => {
|
||||
message.success('更新成功');
|
||||
showEmailModal.value = false;
|
||||
userStore.GetInfo();
|
||||
})
|
||||
.finally(() => {
|
||||
formEmailBtnLoading.value = false;
|
||||
});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openUpdateEmailForm() {
|
||||
showEmailModal.value = true;
|
||||
formEmailValue.value.email = '';
|
||||
formEmailValue.value.code = '';
|
||||
}
|
||||
|
||||
function sendMobileCode() {
|
||||
activateSend(SendBindSms());
|
||||
}
|
||||
|
||||
function sendEmailCode() {
|
||||
activateSend(SendBindEmail());
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
adaModalWidth(dialogWidth, 580);
|
||||
});
|
||||
</script>
|
||||
83
web/src/views/home/account/account.vue
Normal file
83
web/src/views/home/account/account.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-grid cols="24 300:1 600:24" :x-gap="24">
|
||||
<n-grid-item span="6">
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<n-thing
|
||||
class="thing-cell"
|
||||
v-for="item in typeTabList"
|
||||
:key="item.key"
|
||||
:class="{ 'thing-cell-on': type === item.key }"
|
||||
@click="switchType(item)"
|
||||
>
|
||||
<template #header>{{ item.name }}</template>
|
||||
<template #description>{{ item.desc }}</template>
|
||||
</n-thing>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item span="18">
|
||||
<n-card :bordered="false" size="small" :title="typeTitle" class="proCard">
|
||||
<BasicSetting v-if="type === 1" />
|
||||
<SafetySetting v-if="type === 2" />
|
||||
<CashSetting v-if="type === 3" />
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import BasicSetting from './BasicSetting.vue';
|
||||
import SafetySetting from './SafetySetting.vue';
|
||||
import CashSetting from './CashSetting.vue';
|
||||
|
||||
const typeTabList = [
|
||||
{
|
||||
name: '基本设置',
|
||||
desc: '个人账户信息设置',
|
||||
key: 1,
|
||||
},
|
||||
{
|
||||
name: '安全设置',
|
||||
desc: '密码、手机号、邮箱等设置',
|
||||
key: 2,
|
||||
},
|
||||
{
|
||||
name: '提现设置',
|
||||
desc: '提现收款账号支付宝设置',
|
||||
key: 3,
|
||||
},
|
||||
];
|
||||
|
||||
const type = ref(1);
|
||||
const typeTitle = ref('基本设置');
|
||||
|
||||
function switchType(e) {
|
||||
type.value = e.key;
|
||||
typeTitle.value = e.name;
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.thing-cell {
|
||||
margin: 0 -16px 10px;
|
||||
padding: 5px 16px;
|
||||
|
||||
&:hover {
|
||||
background: #f3f3f3;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.thing-cell-on {
|
||||
background: #f0faff;
|
||||
color: #2d8cf0;
|
||||
|
||||
::v-deep(.n-thing-main .n-thing-header .n-thing-header__title) {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f0faff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
153
web/src/views/home/message/list.vue
Normal file
153
web/src/views/home/message/list.vue
Normal file
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<n-spin :show="loading">
|
||||
<n-empty v-show="dataSource.list?.length === 0" description="无数据" />
|
||||
<n-list hoverable clickable class="list-item">
|
||||
<n-list-item v-for="item in dataSource.list" :key="item.id" @click="UnRead(item)">
|
||||
<n-thing
|
||||
content-indented
|
||||
:title="item.title"
|
||||
:description="item.createdAt"
|
||||
:content-style="{ padding: '10px' }"
|
||||
>
|
||||
<template #avatar>
|
||||
<n-badge v-bind="getBadgePops(item)">
|
||||
<n-avatar v-if="item.senderAvatar !== ''" round :size="28" :src="item.senderAvatar" />
|
||||
<n-icon-wrapper v-else :size="28" :border-radius="10">
|
||||
<n-icon :size="20" :component="getIcon(item)" />
|
||||
</n-icon-wrapper>
|
||||
</n-badge>
|
||||
</template>
|
||||
|
||||
<template #header-extra>
|
||||
<n-tag
|
||||
v-if="item.tagTitle !== '' && item.tagTitle !== undefined"
|
||||
v-bind="item.tagProps"
|
||||
size="large"
|
||||
strong
|
||||
>
|
||||
{{ item.tagTitle }}
|
||||
</n-tag>
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<span v-html="item.content"></span>
|
||||
</template>
|
||||
</n-thing>
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</n-spin>
|
||||
|
||||
<n-space justify="end" style="margin-top: 30px">
|
||||
<n-pagination
|
||||
v-model:page="dataSource.page"
|
||||
:page-count="dataSource.pageCount"
|
||||
:page-slot="5"
|
||||
:page-sizes="[5, 10, 50, 100]"
|
||||
size="medium"
|
||||
show-quick-jumper
|
||||
show-size-picker
|
||||
:on-update:page="onUpdatePage"
|
||||
:on-update:page-size="onUpdatePageSize"
|
||||
/>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { MessageRow, parseMessage } from '@/enums/systemMessageEnum';
|
||||
import { getIcon } from '@/enums/systemMessageEnum';
|
||||
import { MessageList, UpRead } from '@/api/apply/notice';
|
||||
import { debounce } from 'throttle-debounce';
|
||||
import { notificationStoreWidthOut } from '@/store/modules/notification';
|
||||
|
||||
interface Props {
|
||||
type?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: '1',
|
||||
});
|
||||
|
||||
interface dataList {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
pageCount: number;
|
||||
list: null | MessageRow[];
|
||||
}
|
||||
|
||||
const dataSource = ref<dataList>({
|
||||
page: 1,
|
||||
pageSize: 5,
|
||||
pageCount: 1,
|
||||
list: [],
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
const notificationStore = notificationStoreWidthOut();
|
||||
|
||||
function loadDataSource() {
|
||||
loading.value = true;
|
||||
MessageList({
|
||||
type: props.type,
|
||||
page: dataSource.value.page,
|
||||
pageSize: dataSource.value.pageSize,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.list?.length > 0) {
|
||||
for (let i = 0; i < res.list.length; i++) {
|
||||
res.list[i] = parseMessage(res.list[i]);
|
||||
}
|
||||
}
|
||||
dataSource.value = res as dataList;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function UnRead(item: MessageRow) {
|
||||
UpRead({ id: item.id })
|
||||
.then(() => {
|
||||
item.isRead = true;
|
||||
debounceCallback();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
const debounceCallback = debounce(1000, function () {
|
||||
notificationStore.pullMessages();
|
||||
});
|
||||
|
||||
function getBadgePops(item: MessageRow) {
|
||||
if (item.isRead) {
|
||||
return {};
|
||||
}
|
||||
return { dot: true, processing: true, offset: [-2, 2] };
|
||||
}
|
||||
function onUpdatePage(page: number) {
|
||||
dataSource.value.page = page;
|
||||
loadDataSource();
|
||||
}
|
||||
|
||||
function onUpdatePageSize(pageSize: number) {
|
||||
dataSource.value.pageSize = pageSize;
|
||||
loadDataSource();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadDataSource();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
::v-deep(.list-item) {
|
||||
margin-left: calc(1vw);
|
||||
margin-right: calc(1vw);
|
||||
}
|
||||
|
||||
:deep(img, video, audio) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
42
web/src/views/home/message/message.vue
Normal file
42
web/src/views/home/message/message.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="我的消息">
|
||||
在这里你可以查看平台中通知、公告和与你相关的私信
|
||||
</n-card>
|
||||
</div>
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<n-tabs
|
||||
type="card"
|
||||
class="card-tabs"
|
||||
:value="defaultTab"
|
||||
size="large"
|
||||
animated
|
||||
@before-leave="handleBeforeLeave"
|
||||
>
|
||||
<n-tab-pane name="1" tab="通知"> <List :type="defaultTab" /></n-tab-pane>
|
||||
<n-tab-pane name="2" tab="公告"> <List :type="defaultTab" /> </n-tab-pane>
|
||||
<n-tab-pane name="3" tab="私信"> <List :type="defaultTab" /> </n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import List from './list.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const router = useRouter();
|
||||
const defaultTab = ref('1');
|
||||
|
||||
onMounted(() => {
|
||||
if (router.currentRoute.value.query?.type) {
|
||||
defaultTab.value = router.currentRoute.value.query.type as string;
|
||||
}
|
||||
});
|
||||
|
||||
function handleBeforeLeave(tabName: string) {
|
||||
defaultTab.value = tabName;
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user