OA体制内聊天新增用户详情页面,并接入真实用户数据,处理数据格式;新增聊天记录按图片与视频搜索,并处理图片排列格式

This commit is contained in:
wangyifeng 2025-01-16 18:25:21 +08:00
parent a3c1b56d27
commit 656fe2e4db
11 changed files with 521 additions and 21 deletions

View File

@ -25,3 +25,12 @@ export const userLeaderApi = (data) => {
baseURL:import.meta.env.VITE_EPR_BASEURL,
})
}
//点击头像查看用户详情
export const getUserInfoByClickAvatar = (data) => {
return request({
url: '/api/v1/users/info',
method: 'POST',
data,
})
}

View File

@ -1,6 +1,17 @@
<template>
<div class="custom-btn" :class="props.isBottom ? 'custom-btn-bottom' : ''">
<wd-button custom-class="custom-btn-class" @click="clickBtn">{{ props.btnText }}</wd-button>
<div
class="custom-btn"
:class="[
props.isBottom ? 'custom-btn-bottom' : '',
props.subBtnText ? 'apposition-btn-style' : '',
]"
>
<wd-button custom-class="custom-sub-btn-class" v-if="props.subBtnText">
{{ props.subBtnText }}
</wd-button>
<wd-button custom-class="custom-btn-class" @click="clickBtn">
{{ props.btnText }}
</wd-button>
</div>
</template>
<script setup>
@ -11,6 +22,7 @@ const emits = defineEmits(['clickBtn'])
const props = defineProps({
isBottom: false, //
btnText: '', //
subBtnText: '', //
})
//
@ -24,6 +36,16 @@ const clickBtn = () => {
flex-direction: row;
align-items: center;
justify-content: center;
.custom-sub-btn-class {
background-color: #eee9f8;
padding: 18rpx 185rpx;
border-radius: 8rpx;
box-shadow: 0 6px 12px 2px rgba(188, 188, 188, 0.08);
font-size: 28rpx;
font-weight: 500;
line-height: 40rpx;
color: $theme-primary;
}
.custom-btn-class {
background-color: $theme-primary;
padding: 18rpx 185rpx;
@ -39,4 +61,14 @@ const clickBtn = () => {
background-color: #fff;
padding: 14rpx 0 72rpx;
}
.apposition-btn-style {
padding: 14rpx 30rpx 72rpx;
.custom-sub-btn-class {
padding: 18rpx 124rpx;
margin: 0 20rpx 0 0;
}
.custom-btn-class {
padding: 18rpx 124rpx;
}
}
</style>

View File

@ -43,7 +43,7 @@
"type": "page",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh":false
"enablePullDownRefresh": false
}
},
{
@ -51,7 +51,7 @@
"type": "page",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh":false
"enablePullDownRefresh": false
}
},
{
@ -170,6 +170,14 @@
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
},
{
"path": "pages/dialog/dialogDetail/userDetail",
"type": "page",
"style": {
"navigationStyle": "custom",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {

View File

@ -3,6 +3,7 @@
<div
class="group-member-list-each"
v-for="(memberItem, memberIndex) in props?.memberList"
@click="toUserDetailPage(memberItem)"
>
<div
class="group-member-each"
@ -40,6 +41,14 @@ const props = defineProps({
memberList: Array, //
memberListsLimit: Number, //
})
//
const toUserDetailPage = (userItem) => {
console.log(userItem.erp_user_id)
uni.navigateTo({
url: '/pages/dialog/dialogDetail/userDetail?erpUserId=' + userItem.erp_user_id,
})
}
</script>
<style scoped lang="scss">
.group-member-list {

View File

@ -0,0 +1,287 @@
<template>
<div class="outer-layer user-detail-page">
<div class="root">
<ZPaging ref="zPaging" :show-scrollbar="false">
<template #top>
<tm-navbar
class="tmNavBar"
:hideBack="false"
hideHome
title=""
:leftWidth="220"
></tm-navbar>
</template>
<div class="user-detail-info">
<div class="user-info-head user-info-card">
<div class="user-info-avatar">
<img
:src="state?.userInfo?.avatar"
v-if="state?.userInfo?.avatar"
/>
<span
v-if="!state?.userInfo?.avatar"
class="text-[46rpx] font-bold"
>
{{
state?.userInfo?.nickname.length >= 2
? state?.userInfo?.nickname.slice(-2)
: state?.userInfo?.nickname
}}
</span>
</div>
<div class="user-info">
<span class="text-[40rpx] font-medium user-info-name">
{{ state?.userInfo?.nickname }}
</span>
<span class="text-[28rpx] font-medium user-info-job-num">
{{ $t('user.info.jobNum') + '' + state?.userInfo?.job_num }}
</span>
</div>
</div>
<div class="user-info-main user-info-card">
<div class="user-info-main-title">
<img src="/src/static/image/mine/ming001@3x.png" />
<span class="text-[28rpx] font-medium">
{{ $t('index.mine.basic') }}
</span>
</div>
<div class="user-info-main-list">
<div
class="user-info-main-each"
v-for="(item, index) in state.userBasicInfos"
:key="index"
>
<span class="text-[28rpx] font-medium user-info-main-each-hint">
{{ item.name }}
</span>
<span class="text-[28rpx] font-medium user-info-main-each-text">
{{ item.value }}
</span>
</div>
</div>
</div>
</div>
<template #bottom>
<customBtn
:isBottom="true"
:btnText="$t('user.detail.sendMsg')"
:subBtnText="$t('user.detail.ringBell')"
></customBtn>
</template>
</ZPaging>
</div>
</div>
</template>
<script setup>
import customBtn from '@/components/custom-btn/custom-btn.vue'
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
import { onLoad } from '@dcloudio/uni-app'
import { reactive } from 'vue'
import { getUserInfoByClickAvatar } from '@/api/user/index'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const state = reactive({
erpUserId: '', //erpid
userInfo: null, //
userBasicInfos: [], //
})
onLoad((options) => {
console.log(options)
if (options.erpUserId) {
state.erpUserId = options.erpUserId
getUserInfo()
}
})
//
const getUserInfo = () => {
let params = {
erp_user_id: Number(state.erpUserId),
}
console.log(params)
const resp = getUserInfoByClickAvatar(params)
console.log(resp)
resp.then(({ code, data }) => {
console.log(data)
if (code == 200) {
state.userInfo = data
let department = ''
let post = ''
if (data?.erp_dept_position?.length > 0) {
data.erp_dept_position.forEach((item) => {
if (!department) {
department = item.department_name
} else {
department = department + '、' + item.department_name
}
if (!post) {
post = item.position_name
} else {
post = post + '、' + item.position_name
}
})
}
let hasAddDepartment = department.split('、')
let uniqueArr = [...new Set(hasAddDepartment)]
department = uniqueArr.join('、')
let manager = ''
if (data?.leaders?.length > 0) {
data.leaders.forEach((item) => {
if (!manager) {
manager = item.user_name
} else {
manager = manager + '、' + item.user_name
}
})
}
state.userBasicInfos = [
{
name: t('index.mine.company'),
value: data.company_name,
},
{
name: t('index.mine.department'),
value: department,
},
{
name: t('index.mine.post'),
value: post,
},
{
name: t('index.mine.manager'),
value: manager,
},
{
name: t('index.mine.phone'),
value: data.tel_num,
},
{
name: t('index.mine.entry'),
value: data.enter_date,
},
]
} else {
}
})
resp.catch(() => {})
}
</script>
<style scoped lang="scss">
.outer-layer {
flex: 1;
background-image: url('@/static/image/mine/1111.png');
background-size: cover;
background-repeat: no-repeat;
}
.tmNavBar {
::v-deep .noNvueBorder {
border-bottom: 0 !important;
background-color: unset !important;
box-shadow: unset !important;
}
}
.user-detail-page {
.user-detail-info {
padding: 86rpx 32rpx 0;
.user-info-card {
background-color: #fff;
box-shadow: 0 6px 12px 2px rgba(188, 188, 188, 0.08);
border-radius: 8rpx;
}
.user-info-head {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 20rpx 32rpx;
.user-info-avatar {
width: 154rpx;
height: 154rpx;
border-radius: 16rpx;
overflow: hidden;
background: linear-gradient(to right, #674bbc, #46299d);
box-shadow: 0 6px 12px 2px rgba(70, 41, 157, 0.16);
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
img {
width: 100%;
height: 100%;
}
span {
line-height: 64rpx;
color: #fff;
}
}
.user-info {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
margin: 0 0 0 32rpx;
.user-info-name {
line-height: 56rpx;
color: $theme-text;
}
.user-info-job-num {
margin: 12rpx 0 0;
line-height: 40rpx;
color: #b4b4b4;
}
}
}
.user-info-main {
margin: 20rpx 0 0;
padding: 0 18rpx;
.user-info-main-title {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 38rpx 12rpx 32rpx;
img {
width: 36rpx;
height: 40rpx;
}
span {
line-height: 40rpx;
color: $theme-text;
margin: 0 0 0 20rpx;
}
}
.user-info-main-list {
.user-info-main-each {
padding: 14rpx;
border-top: 1px solid $theme-border-color;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
.user-info-main-each-hint {
line-height: 40rpx;
color: $theme-text;
width: 112rpx;
white-space: nowrap;
flex-shrink: 0;
}
.user-info-main-each-text {
margin: 0 0 0 56rpx;
line-height: 40rpx;
color: #747474;
}
}
}
}
}
}
</style>

View File

@ -54,7 +54,7 @@
</aside>
<!-- 头像信息 -->
<aside class="avatar-column">
<aside class="avatar-column" @click="toUserDetailPage(item)">
<im-avatar class="pointer" :src="item.avatar" :size="80" :username="item.nickname"
@click="showUserInfoModal(item.user_id)" />
</aside>
@ -693,6 +693,13 @@ const toChatSettingsPage = () => {
})
}
//
const toUserDetailPage = (userItem) => {
uni.navigateTo({
url: '/pages/dialog/dialogDetail/userDetail?erpUserId=' + userItem.erp_user_id,
})
}
onMounted(async () => {
initData()
})

View File

@ -287,6 +287,9 @@ const resultDetail = computed(() => {
width: 64rpx;
height: 64rpx;
margin: 0 18rpx 0 0;
span {
font-size: 20rpx;
}
}
.result-info {
width: 100%;

View File

@ -67,9 +67,19 @@
</div>
<div
class="search-by-condition-input-list"
v-if="state.condition === 'file' || state.condition === 'link'"
v-if="
state.condition === 'imgAndVideo' ||
state.condition === 'file' ||
state.condition === 'link'
"
:style="{
padding: state.condition === 'imgAndVideo' ? '0 27rpx' : '',
}"
>
<div class="search-by-condition-input">
<div
class="search-by-condition-input"
v-if="state.condition === 'file' || state.condition === 'link'"
>
<customInput
:searchText="state.searchText"
:first_talk_record_infos="state.first_talk_record_infos"
@ -95,13 +105,68 @@
{{ conditionItem.dateMonth }}
</span>
</div>
<div class="condition-each-resultList">
<div
class="condition-each-resultList"
:class="[
state.condition === 'imgAndVideo'
? 'condition-type-imgAndVideo-result'
: '',
]"
>
<div
class="condition-each-resultList-each"
v-for="(item, index) in conditionItem.monthResultList"
:key="index"
:style="{
border: state.condition === 'imgAndVideo' ? '0' : '',
padding:
state.condition === 'imgAndVideo' ? '0 0 10rpx' : '',
}"
>
<div class="condition-each-result-main">
<div
class="condition-result-imgAndVideo"
v-if="state.condition === 'imgAndVideo'"
>
<div
class="condition-result-imgAndVideo-area"
v-if="item?.extra?.items?.length > 0"
>
<div
class="condition-result-imgAndVideo-each"
v-for="(imgItem, imgIndex) in item?.extra?.items"
:key="imgIndex"
>
<tm-image
preview
:src="imgItem?.content"
v-if="imgItem?.type == 3"
model="aspectFill"
/>
</div>
</div>
<div
class="condition-result-imgAndVideo-area"
v-if="item?.extra?.url"
>
<tm-image
preview
:src="
item?.msg_type === 3
? item?.extra?.url
: item?.msg_type === 5
? item?.extra?.cover
: ''
"
model="aspectFill"
/>
</div>
</div>
<div
class="condition-each-result-main"
v-if="
state.condition === 'file' || state.condition === 'link'
"
>
<searchItem
:searchItem="item"
:conditionType="state.msg_type"
@ -112,26 +177,63 @@
{{ item.dateTime }}
</span>
</div>
<div class="condition-each-result-attachments">
<div
class="condition-each-result-attachments"
v-if="
state.condition === 'file' || state.condition === 'link'
"
>
<div class="attachment-avatar">
<img :src="item?.extra?.file_avatar" />
<img
:src="item?.extra?.file_avatar"
v-if="state.condition === 'file'"
/>
<img
src="/src/static/image/search/result-link-icon.png"
v-if="state.condition === 'link'"
/>
</div>
<div class="attachment-info">
<div class="attachment-info-title">
<span class="text-[28rpx] font-regular">
<span
class="text-[28rpx] font-regular"
v-if="state.condition === 'file'"
>
{{ item?.extra?.name }}
</span>
<span
class="text-[28rpx] font-regular"
v-if="state.condition === 'link'"
>
{{ $t('record.share.link') }}
</span>
</div>
<div class="attachment-sub-info">
<span class="text-[24rpx] font-regular">
<div
class="attachment-sub-info"
:style="{
margin:
state.condition === 'file' ? '20rpx 0 0' : '',
}"
>
<span
class="text-[24rpx] font-regular"
v-if="state.condition === 'file'"
>
{{ item?.extra?.typeText }}
</span>
<span
class="text-[24rpx] font-regular"
v-if="state.condition === 'file'"
style="margin: 0 0 0 20rpx;"
>
{{ item?.extra?.fileSize }}
</span>
<span
class="text-[24rpx] font-regular"
v-if="state.condition === 'link'"
>
{{ item?.extra?.content }}
</span>
</div>
</div>
</div>
@ -206,6 +308,11 @@ onLoad((options) => {
state.showPageTitle = true
state.pageTitle = t('search.condition.date')
ServeQueryTalkDate(parseTime(state.nowDate, '{y}{m}'))
} else if (options.condition === 'imgAndVideo') {
state.showPageTitle = true
state.pageTitle = t('record.searchType.imgWithVideo')
state.msg_type = '3,5'
queryAllSearch()
} else if (options.condition === 'file') {
console.log(dialogueParams)
let first_talk_record_infos = {
@ -228,7 +335,7 @@ onLoad((options) => {
state.first_talk_record_infos,
first_talk_record_infos,
)
state.msg_type = 0
state.msg_type = 14
queryAllSearch()
}
}
@ -554,16 +661,49 @@ body::v-deep .round-3 {
flex-direction: row;
align-items: center;
justify-content: flex-start;
margin: 20rpx 0 0;
span {
line-height: 34rpx;
color: $theme-hint-text;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
}
}
.condition-type-imgAndVideo-result {
border-bottom: 0;
padding: 0;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
.condition-each-resultList-each {
.condition-result-imgAndVideo {
margin: 0 5rpx;
::v-deep .overflow {
width: 164rpx !important;
height: 164rpx !important;
}
.condition-result-imgAndVideo-area {
::v-deep .overflow {
width: 164rpx !important;
height: 164rpx !important;
}
::v-deep .round-0 {
width: 164rpx !important;
height: 164rpx !important;
}
}
}
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -73,8 +73,7 @@ export const useDialogueStore = defineStore('dialogue', {
getSilenceMember: (state) =>
state.members.filter((item) => item.is_mute === 1),
//获取群管理员
getAdminList: (state) =>
state.members.filter((item) => item.leader === 1),
getAdminList: (state) => state.members.filter((item) => item.leader === 1),
},
actions: {
// 更新在线状态
@ -119,7 +118,8 @@ export const useDialogueStore = defineStore('dialogue', {
remark: o.remark,
online: false,
value: o.nickname,
key: o.key
key: o.key,
erp_user_id: o.erp_user_id,
}))
},

View File

@ -60,7 +60,7 @@
"index.mine.post": "岗位",
"index.mine.manager": "主管",
"index.mine.phone": "手机号",
"index.mine.entry": "入职时间",
"index.mine.entry": "入职日期",
"index.mine.unable": "无法上传照片",
"index.mine.face": "扫脸失败",
"index.mine.recentPhoto": "个人近照",
@ -96,6 +96,7 @@
"search.chat.record": "搜索聊天记录",
"record.searchType.date": "日期",
"record.searchType.imgAndVideo": "图片及视频",
"record.searchType.imgWithVideo": "图片与视频",
"record.searchType.files": "文件",
"record.searchType.link": "链接",
"group.identify.admin": "管理员",
@ -117,5 +118,9 @@
"silence.tag.hasDone": "已禁言",
"chat.manage.addAdmin": "添加管理员",
"search.condition.member": "按群成员查找",
"result.date.nowMonth": "这个月"
"result.date.nowMonth": "这个月",
"user.detail.ringBell": "打电话",
"user.detail.sendMsg": "发消息",
"user.info.jobNum": "工号",
"record.share.link": "分享链接"
}