用户个人中心功能开发v4 - 系统通知静态页开发

pull/1/head
ccongli 1 year ago
parent 35326f1fa6
commit bb82588208

@ -54,18 +54,19 @@ module.exports = defineConfig({
'vue/attribute-hyphenation': 'off',
'vue/require-default-prop': 'off',
'vue/require-explicit-emits': 'off',
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'never',
component: 'always'
},
svg: 'always',
math: 'always'
}
],
// 'vue/html-self-closing': [
// 'error',
// {
// html: {
// void: 'always',
// normal: 'never',
// component: 'always'
// },
// svg: 'always',
// math: 'always'
// }
// ],
"vue/html-self-closing": 0,
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'off'
}

@ -10,25 +10,42 @@
<el-tab-pane :label="t('profile.tabs.LoginRecord')">
<LoginRecord />
</el-tab-pane>
<el-tab-pane :label="t('profile.tabs.SystemNotice')">系统通知</el-tab-pane>
<el-tab-pane :label="t('profile.tabs.SystemNotice')">
<!-- <SystemNotice /> -->
<component ref="noticeRef" :is="noticeComponentTabs[noticeComponent]"
@changeNoticeComponent="changeNoticeComponent" @toNoticeInfo="toNoticeInfo" />
</el-tab-pane>
<el-tab-pane :label="t('profile.tabs.MessageSetting')">消息设置</el-tab-pane>
<el-tab-pane :label="t('profile.tabs.CompanyList')">公司列表</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="ts" name="Profile">
import { nextTick } from 'process'
// import { BasicInfo, ProfileUser, ResetPwd, UserSocial } from './components/'
import { BaseInfo, ResetPwd, LoginRecord } from './components/'
import { BaseInfo, ResetPwd, LoginRecord, SystemNotice, SystemNoticeInfo } from './components/'
const { t } = useI18n()
const state = reactive({
circleUrl: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
dialogVisible: false,
dialogVisible2: false,
});
// notice
const noticeComponentTabs = {
SystemNotice,
SystemNoticeInfo,
}
const noticeRef = ref<any>(null);
const noticeComponent = ref('SystemNotice');
const changeNoticeComponent = (name) => {
noticeComponent.value = name;
}
// notice
const toNoticeInfo = (info) => {
// 使,
nextTick(() => {
// console.log(info);
noticeRef.value.setInfo(info);
});
}
// const activeName = ref('basicInfo')
</script>
<style lang="scss" scoped>

@ -1,99 +0,0 @@
<template>
<div>
<div class="text-center">
<UserAvatar :img="userInfo?.avatar" />
</div>
<ul class="list-group list-group-striped">
<li class="list-group-item">
<Icon class="mr-5px" icon="ep:user" />
{{ t('profile.user.username') }}
<div class="pull-right">{{ userInfo?.username }}</div>
</li>
<li class="list-group-item">
<Icon class="mr-5px" icon="ep:phone" />
{{ t('profile.user.mobile') }}
<div class="pull-right">{{ userInfo?.mobile }}</div>
</li>
<li class="list-group-item">
<Icon class="mr-5px" icon="fontisto:email" />
{{ t('profile.user.email') }}
<div class="pull-right">{{ userInfo?.email }}</div>
</li>
<li class="list-group-item">
<Icon class="mr-5px" icon="carbon:tree-view-alt" />
{{ t('profile.user.dept') }}
<div v-if="userInfo?.dept" class="pull-right">{{ userInfo?.dept.name }}</div>
</li>
<li class="list-group-item">
<Icon class="mr-5px" icon="ep:suitcase" />
{{ t('profile.user.posts') }}
<div v-if="userInfo?.posts" class="pull-right">
{{ userInfo?.posts.map((post) => post.name).join(',') }}
</div>
</li>
<li class="list-group-item">
<Icon class="mr-5px" icon="icon-park-outline:peoples" />
{{ t('profile.user.roles') }}
<div v-if="userInfo?.roles" class="pull-right">
{{ userInfo?.roles.map((role) => role.name).join(',') }}
</div>
</li>
<li class="list-group-item">
<Icon class="mr-5px" icon="ep:calendar" />
{{ t('profile.user.createTime') }}
<div class="pull-right">{{ formatDate(userInfo?.createTime) }}</div>
</li>
</ul>
</div>
</template>
<script lang="ts" setup>
import { formatDate } from '@/utils/formatTime'
import UserAvatar from './UserAvatar.vue'
import { getUserProfile, ProfileVO } from '@/api/system/user/profile'
defineOptions({ name: 'ProfileUser' })
const { t } = useI18n()
const userInfo = ref<ProfileVO>()
const getUserInfo = async () => {
const users = await getUserProfile()
userInfo.value = users
}
onMounted(async () => {
await getUserInfo()
})
</script>
<style scoped>
.text-center {
position: relative;
height: 120px;
text-align: center;
}
.list-group-striped > .list-group-item {
padding-right: 0;
padding-left: 0;
border-right: 0;
border-left: 0;
border-radius: 0;
}
.list-group {
padding-left: 0;
list-style: none;
}
.list-group-item {
padding: 11px 0;
margin-bottom: -1px;
font-size: 13px;
border-top: 1px solid #e7eaec;
border-bottom: 1px solid #e7eaec;
}
.pull-right {
float: right !important;
}
</style>

@ -0,0 +1,204 @@
<template>
<div class="container system-notice">
<div class="subject">
<div class="lc"></div>
<div class="lh">系统通知</div>
</div>
<div class="content">
<div class="types">
<template v-for="(item, index) in types" :key="index">
<el-button :type="item.type == activeIndex ? 'primary' : 'default'" plain
@click="changeNoticeType(item.type)">{{ item.name }}</el-button>
</template>
<div class="yidu">
<el-button type="info" :icon="Check">全部标记为已读</el-button>
</div>
</div>
<div class="list">
<el-table :data="noticeList" height="590" :header-cell-style="{ 'background-color': '#f2f2f2' }"
:row-style="{ 'height': '55px', 'cursor': 'pointer' }" style="width: 100%" stripe @row-click="noticeInfoClick">
<el-table-column prop="title" label="标题" />
<el-table-column prop="status" label="状态" width="120">
<template #default="scope">
<div style="display: flex; align-items: center">
<template v-if="scope.row.status == 1">
<el-badge is-dot type="danger" style="margin: 10px 10px 0 0;">
<el-button size="small" plain>已读</el-button>
</el-badge>
</template>
<template v-else>
<el-badge is-dot type="success" style="margin: 10px 10px 0 0;">
<el-button size="small" plain>未读</el-button>
</el-badge>
</template>
</div>
</template>
</el-table-column>
<el-table-column prop="type" label="类型" width="120" />
<el-table-column prop="createTime" label="发布时间" width="180" />
</el-table>
</div>
<div class="page">
<el-pagination background layout="prev, pager, next" :total="page.total" hide-on-single-page
v-model:current-page="page.current" v-model:page-size="page.pageSize" @current-change="handleCurrentChange" />
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { Check } from '@element-plus/icons-vue'
defineOptions({ name: 'SystemNotice' })
const { t } = useI18n()
const message = useMessage()
const emits = defineEmits(['changeNoticeComponent', 'toNoticeInfo'])
const types = ref<any>([
{
type: 0,
name: '全部消息',
},
{
type: 1,
name: '服务消息',
},
{
type: 2,
name: '活动消息',
},
{
type: 3,
name: '商品消息',
},
{
type: 4,
name: '安全消息',
},
{
type: 5,
name: '故障消息',
}
]);
const activeIndex = ref<number>(0);
const noticeList = ref<any>([]);
const page = reactive({
current: 1,
pageSize: 10,
total: 100
});
onMounted(() => {
getNoiceData();
});
const getNoiceData = () => {
noticeList.value = [
{
'id': 1,
'title': '供应链管理平台正式上线1',
'status': 1,
'type': '商品消息',
'createTime': '2022-08-22 18:05:11',
},
{
'id': 2,
'title': '供应链管理平台正式上线2',
'status': 1,
'type': '商品消息',
'createTime': '2022-08-22 18:05:11',
},
{
'id': 3,
'title': '供应链管理平台正式上线3',
'status': 2,
'type': '商品消息',
'createTime': '2022-08-22 18:05:11',
},
{
'id': 4,
'title': '供应链管理平台正式上线4',
'status': 2,
'type': '商品消息',
'createTime': '2022-08-22 18:05:11',
},
{
'id': 5,
'title': '供应链管理平台正式上线5',
'status': 1,
'type': '商品消息',
'createTime': '2022-08-22 18:05:11',
},
]
};
//
const changeNoticeType = (type: number) => {
activeIndex.value = type;
// todo
}
//
const handleCurrentChange = (val: number) => {
console.log(`current page: ${val}`)
}
//
const noticeInfoClick = (row, column, event) => {
emits('changeNoticeComponent', 'SystemNoticeInfo');
emits('toNoticeInfo', row);
}
</script>
<style lang="scss" scoped>
.system-notice {
width: 100%;
padding: 20px;
padding-left: 50px;
box-sizing: border-box;
.subject {
height: 60px;
color: #666;
display: flex;
align-items: center;
line-height: 20px;
.lc {
width: 8px;
height: 20px;
background: #409eff;
margin-right: 10px;
}
.lh {
color: #666;
font-size: 20px;
font-weight: 700;
}
}
.content {
width: 100%;
.types {
height: 50px;
line-height: 50px;
margin-bottom: 10px;
.yidu {
float: right;
}
}
}
.page {
float: right;
margin-top: 30px;
}
}
</style>

@ -0,0 +1,109 @@
<template>
<div class="container system-notice-info">
<div class="head">
<div class="title">{{info.title}}</div>
<div class="back">
<el-button :type="info" link :icon="Back" @click="backList"></el-button>
</div>
</div>
<div class="tabbar">
<span style="margin-right: 15px;">消息类型<b style="color: #333;">{{info.type}}</b></span>
<span>发布时间<b style="color: #333;">{{info.createTime}}</b></span>
</div>
<div class="content" v-html="defaultContent"></div>
</div>
</template>
<script lang="ts" setup>
import { Back } from '@element-plus/icons-vue'
const { t } = useI18n()
const message = useMessage()
const emits = defineEmits(['changeNoticeComponent'])
const info = ref<any>({ "id": 10086 });
const defaultContent = ref<string>(`
<div>
8月22日由长江云息打造的供应链管理平台正式上线运行该项目基于云息云建设涵盖采购需求采购价格采购配额采购订单到货签收质量协同对账开票付款计划 / 付款申请等全业务流程助力客户实现对标准采购VMI
采购委外加工等业务的全面管理实现供应商全周期管理实现从需求寻源合同到采购执行的全过程管理打造具有云息特色的端到端的数智化供应链管理体系
<br/>
长江云息深知数智化全球化国产化三浪叠加的时代客户之间的竞争不再是单个客户的竞争而是整个价值链供应链产业链的综合竞争为进一步提升全球客户区域运行一体化能力支撑管理数智化战略落地云息加快推进供应链管理变革
<br/>
结合客户业务特点与发展诉求云息供应链主要聚焦四大重点方向
<br/>
" 四个协同 " 为基础实现从 " 集中采购 " " 战略采购 "
转型推进设计协同从执行采购和供应转变为从设计源头管理需求推进采购协同从被动响应转变为主动为业务提供解决方案推进计划协同从被动执行转变为打通计划信息提升前瞻性保障供应链安全推进服务协同从自动化转变高效智能的数字化服务平台赋能业务发展
<br/>
以业务流程为牵引建设客户统一的数智化电子采购平台通过系统配置方式快速搭建采购门户用于供应商注册申请采购寻源及中标信息发布采购政策供应商操作手册发布等
<br/>
以客户统一适用为基础搭建供应商全生命周期管理系统供应商管理功能包括供应商准入供应商认证供应商评价供应商状态管理供应商画像等并可实现与供应商在线协同
<br/>
打通 SAP 端口设立统一集成平台系统集成原则上通过 SAP POProcess Orchestration集成平台完成避免系统间直连MESWMSQMSMOM 等系统先与 SAP 集成再由 SRM 集成
<br/>
云息将持续优化服务与方案供采购寻源电子合同电子签章等服务助力客户加快打造数智化供应链管理体系树立离散制造行业的数智化标杆
</div>
`);
const setInfo = (data) => {
console.log(data);
info.value = data;
}
//
defineExpose({
setInfo
});
//
const backList = () => {
emits('changeNoticeComponent', 'SystemNotice');
}
</script>
<style lang="scss" scoped>
.system-notice-info {
width: 100%;
padding: 20px;
padding-left: 50px;
box-sizing: border-box;
min-height: 750px;
.head {
height: 50px;
line-height: 50px;
.title {
width: 85%;
display: inline-block;
color: #666;
font-weight: 700;
font-size: 20px;
}
.back {
float: right;
display: inline-block;
}
}
.tabbar {
height: 35px;
padding-left: 10px;
font-size: 12px;
border: 1px solid #e4e4e4;
background-color: #f9f9f9;
color: #666;
line-height: 35px;
margin-bottom: 15px;
}
.content {
height: 750px;
color: #666;
font-size: 16px;
line-height: 32px;
}
}
</style>

@ -1,39 +0,0 @@
<template>
<div class="change-avatar">
<CropperAvatar
ref="cropperRef"
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
:showBtn="false"
:value="img"
width="120px"
@change="handelUpload"
/>
</div>
</template>
<script lang="ts" setup>
import { propTypes } from '@/utils/propTypes'
import { uploadAvatar } from '@/api/system/user/profile'
import { CropperAvatar } from '@/components/Cropper'
defineOptions({ name: 'UserAvatar' })
defineProps({
img: propTypes.string.def('')
})
const cropperRef = ref()
const handelUpload = async ({ data }) => {
await uploadAvatar({ avatarFile: data })
cropperRef.value.close()
}
</script>
<style lang="scss" scoped>
.change-avatar {
img {
display: block;
margin-bottom: 15px;
border-radius: 50%;
}
}
</style>

@ -1,94 +0,0 @@
<template>
<el-table :data="socialUsers" :show-header="false">
<el-table-column fixed="left" title="序号" type="seq" width="60" />
<el-table-column align="left" label="社交平台" width="120">
<template #default="{ row }">
<img :src="row.img" alt="" class="h-5 align-middle" />
<p class="mr-5">{{ row.title }}</p>
</template>
</el-table-column>
<el-table-column align="center" label="操作">
<template #default="{ row }">
<template v-if="row.openid">
已绑定
<XTextButton class="mr-5" title="(解绑)" type="primary" @click="unbind(row)" />
</template>
<template v-else>
未绑定
<XTextButton class="mr-5" title="(绑定)" type="primary" @click="bind(row)" />
</template>
</template>
</el-table-column>
</el-table>
</template>
<script lang="ts" setup>
import { SystemUserSocialTypeEnum } from '@/utils/constants'
import { getUserProfile, ProfileVO } from '@/api/system/user/profile'
import { socialAuthRedirect, socialBind, socialUnbind } from '@/api/system/user/socialUser'
defineOptions({ name: 'UserSocial' })
const message = useMessage()
const socialUsers = ref<any[]>([])
const userInfo = ref<ProfileVO>()
const initSocial = async () => {
const res = await getUserProfile()
userInfo.value = res
for (const i in SystemUserSocialTypeEnum) {
const socialUser = { ...SystemUserSocialTypeEnum[i] }
socialUsers.value.push(socialUser)
if (userInfo.value?.socialUsers) {
for (const j in userInfo.value.socialUsers) {
if (socialUser.type === userInfo.value.socialUsers[j].type) {
socialUser.openid = userInfo.value.socialUsers[j].openid
break
}
}
}
}
}
const route = useRoute()
const bindSocial = () => {
//
const type = route.query.type
const code = route.query.code
const state = route.query.state
if (!code) {
return
}
socialBind(type, code, state).then(() => {
message.success('绑定成功')
initSocial()
})
}
const bind = (row) => {
const redirectUri = location.origin + '/user/profile?type=' + row.type
//
socialAuthRedirect(row.type, encodeURIComponent(redirectUri)).then((res) => {
window.location.href = res
})
}
const unbind = async (row) => {
const res = await socialUnbind(row.type, row.openid)
if (res) {
row.openid = undefined
}
message.success('解绑成功')
}
onMounted(async () => {
await initSocial()
})
watch(
() => route,
(newRoute) => {
bindSocial()
console.log(newRoute)
},
{
immediate: true
}
)
</script>

@ -1,8 +1,7 @@
import BaseInfo from './BaseInfo.vue'
import LoginRecord from './LoginRecord.vue'
import ResetPwd from './ResetPwd.vue'
import ProfileUser from './ProfileUser.vue'
import UserAvatarVue from './UserAvatar.vue'
import UserSocial from './UserSocial.vue'
import SystemNotice from './SystemNotice.vue'
import SystemNoticeInfo from './SystemNoticeInfo.vue'
export { BaseInfo, ResetPwd, LoginRecord,ProfileUser, UserAvatarVue, UserSocial }
export { BaseInfo, ResetPwd, LoginRecord, SystemNotice, SystemNoticeInfo }

Loading…
Cancel
Save