Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d97ecfb43 | ||
|
|
e47d5b4dd8 | ||
|
|
1b46d70bea | ||
|
|
902491bc1a | ||
|
|
3b76d28edc | ||
|
|
0ac2f70143 | ||
|
|
5aca3ebe39 | ||
|
|
e7ef2ac975 | ||
|
|
47c255157a | ||
| be54f97bab | |||
| 3e09131356 | |||
|
|
f8ff13639d |
@ -3,3 +3,4 @@ MP_CACHE_PREFIX=production
|
|||||||
MP_WX_APP_ID=wx6ee11733526b4f04
|
MP_WX_APP_ID=wx6ee11733526b4f04
|
||||||
MP_TIM_SDK_APP_ID=1600136080
|
MP_TIM_SDK_APP_ID=1600136080
|
||||||
MP_CORP_ID=wpLgjyawAA8N0gWmXgyJq8wpjGcOT7fg
|
MP_CORP_ID=wpLgjyawAA8N0gWmXgyJq8wpjGcOT7fg
|
||||||
|
MP_VERIFY_IM_CORP_ID=YES
|
||||||
8
App.vue
8
App.vue
@ -196,6 +196,10 @@ page {
|
|||||||
padding-top: 10rpx;
|
padding-top: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pt-12 {
|
||||||
|
padding-top: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.pt-15 {
|
.pt-15 {
|
||||||
padding-top: 30rpx;
|
padding-top: 30rpx;
|
||||||
}
|
}
|
||||||
@ -251,6 +255,10 @@ page {
|
|||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mt-5 {
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.mt-10 {
|
.mt-10 {
|
||||||
margin-top: 20rpx;
|
margin-top: 20rpx;
|
||||||
}
|
}
|
||||||
|
|||||||
89
components/form-template/form-cell/form-positive-find.vue
Normal file
89
components/form-template/form-cell/form-positive-find.vue
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<template>
|
||||||
|
<view class="textarea-row py-12 px-15">
|
||||||
|
<view class="flex justify-between items-center" @click="addRow()">
|
||||||
|
<view class="form-row__label text-base">
|
||||||
|
{{ name || '阳性发现' }}<text v-if="required" class="form-cell--required"></text>
|
||||||
|
</view>
|
||||||
|
<view class="pl-5">
|
||||||
|
<uni-icons type="plus" size="20" color="#0074ff"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-for="(i, idx) in value" :key="idx" class="pt-12" :class="idx > 0 ? 'mt-12 border-t' : ''">
|
||||||
|
<view class="flex justify-between items-center">
|
||||||
|
<view class="text-base text-dark">{{ idx + 1 }}、阳性发现</view>
|
||||||
|
<view class="pl-5" @click="remove(idx)">
|
||||||
|
<uni-icons type="minus" size="20" color="#f87171"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="border p-10 mt-12 rounded-sm">
|
||||||
|
<textarea v-model="i.category" :auto-height="true" class="w-full h-full"></textarea>
|
||||||
|
</view>
|
||||||
|
<view class="text-base mt-12 text-dark">处理意见</view>
|
||||||
|
<view class="border p-10 mt-12 rounded-sm">
|
||||||
|
<textarea v-model="i.opinion" :auto-height="true" class="w-full h-full"></textarea>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const emits = defineEmits(['change']);
|
||||||
|
const props = defineProps({
|
||||||
|
form: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disableChange: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const value = computed(() => Array.isArray(props.form[props.title]) ? props.form[props.title] : [])
|
||||||
|
|
||||||
|
function addRow() {
|
||||||
|
if (props.disableChange) return;
|
||||||
|
const len = value.value.length;
|
||||||
|
if (len === 0) {
|
||||||
|
return change([{ category: '', opinion: '' }])
|
||||||
|
}
|
||||||
|
const last = value.value[len - 1];
|
||||||
|
const category = last.category || '';
|
||||||
|
const opinion = last.opinion || '';
|
||||||
|
if (category === '' && opinion === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
change([...value.value, { category: '', opinion: '' }])
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(idx) {
|
||||||
|
if (props.disableChange) return;
|
||||||
|
change(value.value.filter((i, j) => j !== idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
function change(e) {
|
||||||
|
emits('change', {
|
||||||
|
title: props.title,
|
||||||
|
value: e
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '../cell-style.css';
|
||||||
|
|
||||||
|
.border-t {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -6,11 +6,12 @@
|
|||||||
<view class="flex flex-wrap">
|
<view class="flex flex-wrap">
|
||||||
<view v-for="(file, idx) in files" :key="idx" class="upload-item mt-10">
|
<view v-for="(file, idx) in files" :key="idx" class="upload-item mt-10">
|
||||||
<image v-if="file.isImage" :src="file.url" class="w-full h-full"></image>
|
<image v-if="file.isImage" :src="file.url" class="w-full h-full"></image>
|
||||||
|
<image v-else-if="file.isPdf" src="/static/pdf.svg" class="w-full h-full"></image>
|
||||||
<image v-else src="/static/file.svg" class="w-full h-full"></image>
|
<image v-else src="/static/file.svg" class="w-full h-full"></image>
|
||||||
<uni-icons type="close" :size="32" color="red" class="remove-icon" @click="remove(idx)"></uni-icons>
|
<uni-icons type="close" :size="32" color="red" class="remove-icon" @click="remove(idx)"></uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="value.length < 3"
|
<view v-if="value.length < 10"
|
||||||
class="upload-item border-primary mt-10 flex items-center justify-center text-primary" @click="addImage()">
|
class="upload-item border-primary mt-10 flex items-center justify-center text-primary" @click="chooseType()">
|
||||||
<uni-icons type="camera" :size="40" color="#0074ff"></uni-icons>
|
<uni-icons type="camera" :size="40" color="#0074ff"></uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -48,10 +49,73 @@ const files = computed(() => value.value.map(i => {
|
|||||||
url: i.url,
|
url: i.url,
|
||||||
name: i.name,
|
name: i.name,
|
||||||
type: i.type,
|
type: i.type,
|
||||||
isImage: /image/i.test(i.type)
|
isImage: /image/i.test(i.type),
|
||||||
|
isPdf: /application\/pdf/i.test(i.type),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
function chooseType() {
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: ['图片', 'PDF'],
|
||||||
|
success: (res) => {
|
||||||
|
if (res.tapIndex === 0) {
|
||||||
|
addImage()
|
||||||
|
} else if (res.tapIndex === 1) {
|
||||||
|
addPdf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPdf() {
|
||||||
|
wx.chooseMessageFile({
|
||||||
|
count: 1, // 最多选择1个文件
|
||||||
|
type: 'all', // 所有类型文件
|
||||||
|
success: async (res) => {
|
||||||
|
const file = res.tempFiles[0];
|
||||||
|
const { path, name, size } = file;
|
||||||
|
const type = checkFileValid(name, size);
|
||||||
|
// 检查文件类型和大小
|
||||||
|
if (!type) return;
|
||||||
|
loading();
|
||||||
|
const result = await upload(path);
|
||||||
|
hideLoading();
|
||||||
|
if (result) {
|
||||||
|
change([...value.value, { url: result, type }])
|
||||||
|
} else {
|
||||||
|
toast('上传失败')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
if (/cancel/i.test(err.errMsg)) {
|
||||||
|
// toast('用户取消选择文件')
|
||||||
|
} else {
|
||||||
|
toast('上传失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkFileValid(fileName, fileSize) {
|
||||||
|
// 获取文件扩展名
|
||||||
|
const ext = fileName.split('.').pop().toLowerCase();
|
||||||
|
// 文件大小限制 (10MB)
|
||||||
|
const maxSize = 10 * 1024 * 1024;
|
||||||
|
if (fileSize > maxSize) {
|
||||||
|
toast('文件大小不能超过10MB')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['jpg', 'jpeg', 'png'].includes(ext)) {
|
||||||
|
return 'image/png'
|
||||||
|
}
|
||||||
|
if (ext === 'pdf') {
|
||||||
|
return 'application/pdf'
|
||||||
|
}
|
||||||
|
toast('仅支持图片或PDF')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function addImage() {
|
function addImage() {
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 1,
|
count: 1,
|
||||||
@ -64,6 +128,13 @@ function addImage() {
|
|||||||
} else {
|
} else {
|
||||||
toast('上传失败')
|
toast('上传失败')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
if (/cancel/i.test(err.errMsg)) {
|
||||||
|
// toast('用户取消选择文件')
|
||||||
|
} else {
|
||||||
|
toast('上传失败')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- <view class="px-10">{{ attrs.name }} {{ attrs.title }} {{ attrs.type }}</view> -->
|
<!-- <view class="text-danger px-10">{{ attrs.name }} {{ attrs.title }} {{ attrs.type }}</view> -->
|
||||||
<form-datepicker v-if="attrs.type === 'date'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
<form-datepicker v-if="attrs.type === 'date'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
||||||
@change="change" />
|
@change="change" />
|
||||||
<form-input v-else-if="attrs.type === 'input'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
<form-input v-else-if="attrs.type === 'input'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
||||||
@ -18,6 +18,7 @@
|
|||||||
@addRule="addRule"></form-mult-disease>
|
@addRule="addRule"></form-mult-disease>
|
||||||
<form-upload v-else-if="attrs.type === 'files'" v-bind="attrs" :form="form" @change="change" />
|
<form-upload v-else-if="attrs.type === 'files'" v-bind="attrs" :form="form" @change="change" />
|
||||||
<form-mult-other v-else-if="attrs.type === 'multiSelectAndOther'" v-bind="attrs" :form="form" @change="change" />
|
<form-mult-other v-else-if="attrs.type === 'multiSelectAndOther'" v-bind="attrs" :form="form" @change="change" />
|
||||||
|
<form-positive-find v-else-if="attrs.type === 'positiveFind'" v-bind="attrs" :form="form" @change="change" />
|
||||||
<!--
|
<!--
|
||||||
<form-operation v-else-if="attrs.title === 'surgicalHistory'" v-bind="attrs" :form="form" @change="change"
|
<form-operation v-else-if="attrs.title === 'surgicalHistory'" v-bind="attrs" :form="form" @change="change"
|
||||||
@addRule="addRule" />
|
@addRule="addRule" />
|
||||||
@ -39,6 +40,7 @@ import formTextarea from './form-textarea.vue';
|
|||||||
import formMultDisease from './form-multiple-diseases.vue';
|
import formMultDisease from './form-multiple-diseases.vue';
|
||||||
import formUpload from './form-upload.vue';
|
import formUpload from './form-upload.vue';
|
||||||
import formMultOther from './form-mult-select-and-other.vue';
|
import formMultOther from './form-mult-select-and-other.vue';
|
||||||
|
import formPositiveFind from './form-positive-find.vue';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
form: {
|
form: {
|
||||||
|
|||||||
@ -32,7 +32,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const formCellType = ['input', 'select', 'date', 'radio', 'region', 'textarea', 'multiSelectAndOther', 'selfMultipleDiseases', 'files','diagnosis'];
|
const formCellType = ['input', 'select', 'date', 'radio', 'region', 'textarea', 'multiSelectAndOther', 'selfMultipleDiseases', 'files','diagnosis','positiveFind'];
|
||||||
const formCellTitle = ['surgicalHistory'];
|
const formCellTitle = ['surgicalHistory'];
|
||||||
const customCellType = ['BMI', 'bloodPressure'];
|
const customCellType = ['BMI', 'bloodPressure'];
|
||||||
const disabledMap = computed(() => props.disableTitles.reduce((m, i) => {
|
const disabledMap = computed(() => props.disableTitles.reduce((m, i) => {
|
||||||
|
|||||||
300
pages.json
300
pages.json
@ -8,48 +8,6 @@
|
|||||||
"disableScroll": true
|
"disableScroll": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "pages/article/article-list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "我的宣教",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/article/article-cate-list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "健康宣教",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/survey/survey-list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "我的问卷",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/survey/fill",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "问卷",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/rate/rate-list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "服务评价",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/rate/rate-detail",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "服务评价",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "pages/message/message",
|
"path": "pages/message/message",
|
||||||
"style": {
|
"style": {
|
||||||
@ -65,6 +23,20 @@
|
|||||||
"disableScroll": true
|
"disableScroll": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/mine",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "我的",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/contact",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "联系客服",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/login/login",
|
"path": "pages/login/login",
|
||||||
"style": {
|
"style": {
|
||||||
@ -87,90 +59,6 @@
|
|||||||
"disableScroll": true
|
"disableScroll": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "pages/archive/archive-manage",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "档案管理",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/archive/edit-archive",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "新增档案",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/archive/archive-result",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "团队服务",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "健康信息",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/record",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "健康信息",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/library/diagnosis-list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "选择诊断",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/team/team-detail",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "团队介绍",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/team/homepage",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "个人主页",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/team/friend",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "添加好友",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/web-view/web-view",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/mine/mine",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "我的",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/mine/contact",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "联系客服",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "pages/common/privacy",
|
"path": "pages/common/privacy",
|
||||||
"style": {
|
"style": {
|
||||||
@ -186,19 +74,175 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/article/article-detail",
|
"path": "pages/web-view/web-view",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subPackages": [
|
||||||
|
{
|
||||||
|
"root": "pages/article",
|
||||||
|
"name": "article",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "article-list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "我的宣教",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "article-cate-list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "健康宣教",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "article-detail",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "宣教文章",
|
"navigationBarTitleText": "宣教文章",
|
||||||
"disableScroll": true
|
"disableScroll": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/article/send-article",
|
"path": "send-article",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "选择宣教文章",
|
"navigationBarTitleText": "选择宣教文章",
|
||||||
"disableScroll": true
|
"disableScroll": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/survey",
|
||||||
|
"name": "survey",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "survey-list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "我的问卷",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "fill",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "问卷",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/rate",
|
||||||
|
"name": "rate",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "rate-list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "服务评价",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "rate-detail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "服务评价",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/archive",
|
||||||
|
"name": "archive",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "archive-manage",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "档案管理",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "edit-archive",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "新增档案",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "archive-result",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "团队服务",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health",
|
||||||
|
"name": "health",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "健康信息",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "record",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "健康信息",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/library",
|
||||||
|
"name": "library",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "diagnosis-list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "选择诊断",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/team",
|
||||||
|
"name": "team",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "team-detail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "团队介绍",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "homepage",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "个人主页",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "friend",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "添加好友",
|
||||||
|
"disableScroll": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
"navigationBarTextStyle": "white",
|
"navigationBarTextStyle": "white",
|
||||||
|
|||||||
@ -51,6 +51,9 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
|
<template #footer>
|
||||||
|
<button-footer :showCancel="false" confirmText="返回首页" @confirm="backHome" />
|
||||||
|
</template>
|
||||||
</full-page>
|
</full-page>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -62,6 +65,7 @@ import useAccount from '@/store/account';
|
|||||||
import api from '@/utils/api';
|
import api from '@/utils/api';
|
||||||
|
|
||||||
import FullPage from '@/components/full-page.vue';
|
import FullPage from '@/components/full-page.vue';
|
||||||
|
import buttonFooter from '@/components/button-footer.vue';
|
||||||
|
|
||||||
const team = ref(null);
|
const team = ref(null);
|
||||||
const { useLoad } = useGuard();
|
const { useLoad } = useGuard();
|
||||||
@ -104,6 +108,10 @@ async function getTeam(corpId, teamId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function backHome() {
|
||||||
|
uni.switchTab({ url: '/pages/home/home' })
|
||||||
|
}
|
||||||
|
|
||||||
useLoad(options => {
|
useLoad(options => {
|
||||||
corpId.value = options.corpId;
|
corpId.value = options.corpId;
|
||||||
if (options.teamId && options.corpId) {
|
if (options.teamId && options.corpId) {
|
||||||
|
|||||||
@ -84,6 +84,7 @@ import { storeToRefs } from "pinia";
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import api from "@/utils/api.js";
|
import api from "@/utils/api.js";
|
||||||
import useAccountStore from "@/store/account.js";
|
import useAccountStore from "@/store/account.js";
|
||||||
|
import { toast } from "@/utils/widget.js";
|
||||||
|
|
||||||
import fullPage from "@/components/full-page.vue";
|
import fullPage from "@/components/full-page.vue";
|
||||||
import EmptyData from "@/components/empty-data.vue";
|
import EmptyData from "@/components/empty-data.vue";
|
||||||
@ -138,6 +139,7 @@ const mapRowToView = (row) => {
|
|||||||
person: row?.customer?.name || "",
|
person: row?.customer?.name || "",
|
||||||
team: row?.team?.name || "-",
|
team: row?.team?.name || "-",
|
||||||
time: sendTime,
|
time: sendTime,
|
||||||
|
articleInfo: row?.articleInfo,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -196,8 +198,50 @@ const loadArticleList = async (reset = false) => {
|
|||||||
|
|
||||||
function goToDetail(item) {
|
function goToDetail(item) {
|
||||||
if (!item?.articleId) return;
|
if (!item?.articleId) return;
|
||||||
|
if (isWechatChannels(item.articleInfo)) {
|
||||||
|
uni.openChannelsActivity({
|
||||||
|
finderUserName: item.articleInfo.wechatChannels.finderUserName,
|
||||||
|
feedId: item.articleInfo.wechatChannels.feedId,
|
||||||
|
success: () => {
|
||||||
|
markArticleRead(item._id, item.articleId);
|
||||||
|
},
|
||||||
|
fail: err => {
|
||||||
|
const errMsg = err.errMsg || '';
|
||||||
|
if (/cancel/i.test(errMsg)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toast(`打开视频号失败:${errMsg}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
uni.navigateTo({ url: `/pages/article/article-detail?sendId=${item._id}&id=${item.articleId}&corpId=${corpId.value}` });
|
uni.navigateTo({ url: `/pages/article/article-detail?sendId=${item._id}&id=${item.articleId}&corpId=${corpId.value}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isWechatChannels(item) {
|
||||||
|
return item?.wechatChannels?.finderUserName && item?.wechatChannels?.feedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function markArticleRead(sendId, articleId) {
|
||||||
|
const unionid = account.value?.unionid;
|
||||||
|
if (!unionid || !articleId) return;
|
||||||
|
try {
|
||||||
|
const { success } = await api(
|
||||||
|
"addArticleReadRecord",
|
||||||
|
{ corpId: corpId.value, articleId, unionid, sendId },
|
||||||
|
false
|
||||||
|
);
|
||||||
|
if (success) {
|
||||||
|
const idx = articles.value.findIndex(i => i._id === sendId);
|
||||||
|
if (idx !== -1) {
|
||||||
|
articles.value[idx].status = "YES";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("markArticleRead failed:", err?.message || err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onLoad(opts => {
|
onLoad(opts => {
|
||||||
corpId.value = opts.corpId;
|
corpId.value = opts.corpId;
|
||||||
teamId.value = opts.teamId;
|
teamId.value = opts.teamId;
|
||||||
|
|||||||
@ -40,6 +40,8 @@
|
|||||||
class="mr-5 px-10 leading-normal text-white text-base bg-warning rounded-full">门诊信息</view>
|
class="mr-5 px-10 leading-normal text-white text-base bg-warning rounded-full">门诊信息</view>
|
||||||
<view v-else-if="i.medicalType === 'inhospital'"
|
<view v-else-if="i.medicalType === 'inhospital'"
|
||||||
class="mr-5 px-10 leading-normal text-white text-base bg-success rounded-full">住院信息</view>
|
class="mr-5 px-10 leading-normal text-white text-base bg-success rounded-full">住院信息</view>
|
||||||
|
<view v-if="i.medicalType === 'physicalExaminationTemplate'"
|
||||||
|
class="mr-5 px-10 leading-normal text-white text-base bg-danger rounded-full">体检报告</view>
|
||||||
<view v-if="i.corp === '其他'" class="px-10 leading-normal text-white text-base bg-danger rounded-full">
|
<view v-if="i.corp === '其他'" class="px-10 leading-normal text-white text-base bg-danger rounded-full">
|
||||||
外院
|
外院
|
||||||
</view>
|
</view>
|
||||||
@ -51,7 +53,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view v-if="i.rows.length" class="px-15 border-b">
|
<view v-if="i.rows.length" class="px-15 border-b">
|
||||||
<view v-for="row in i.rows" :key="row.key" class="flex leading-normal mb-10">
|
<view v-for="row in i.rows" :key="row.key" class="flex leading-normal mb-10">
|
||||||
<view class="flex-shrink-0 mr-5 w-90 text-base text-gray">{{ row.label }}:</view>
|
<view class="flex-shrink-0 mr-5 min-w-90 text-base text-gray">{{ row.label }}:</view>
|
||||||
<view v-if="row.title === 'diagnosisName'" class="w-0 flex-grow text-base text-dark">
|
<view v-if="row.title === 'diagnosisName'" class="w-0 flex-grow text-base text-dark">
|
||||||
{{ row.value && row.value.join ? row.value.join(', ') : '' }}
|
{{ row.value && row.value.join ? row.value.join(', ') : '' }}
|
||||||
</view>
|
</view>
|
||||||
@ -96,7 +98,8 @@ import { toast } from '../../utils/widget';
|
|||||||
|
|
||||||
const tempType = {
|
const tempType = {
|
||||||
outpatient: '门诊信息',
|
outpatient: '门诊信息',
|
||||||
inhospital: '住院信息'
|
inhospital: '住院信息',
|
||||||
|
physicalExaminationTemplate: '体检报告'
|
||||||
}
|
}
|
||||||
const empty = ref(false)
|
const empty = ref(false)
|
||||||
const { useLoad, useShow } = useGuard();
|
const { useLoad, useShow } = useGuard();
|
||||||
@ -118,6 +121,7 @@ const tempShowField = ref(null);
|
|||||||
const config = {
|
const config = {
|
||||||
outpatient: ["corp", "deptName", "doctor", "diagnosisName", "files"],
|
outpatient: ["corp", "deptName", "doctor", "diagnosisName", "files"],
|
||||||
inhospital: ["corp", "diagnosisName", "operation", "operationDate", "outhosDate", "files"],
|
inhospital: ["corp", "diagnosisName", "operation", "operationDate", "outhosDate", "files"],
|
||||||
|
physicalExaminationTemplate: ['inspectPakageName']
|
||||||
};
|
};
|
||||||
|
|
||||||
function addArchive() {
|
function addArchive() {
|
||||||
@ -197,7 +201,7 @@ async function getList() {
|
|||||||
memberId: customerId.value,
|
memberId: customerId.value,
|
||||||
page: page.value,
|
page: page.value,
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
medicalType: ['outpatient', 'inhospital']
|
medicalType: Object.keys(tempType)
|
||||||
}
|
}
|
||||||
if (type.value !== 'all') {
|
if (type.value !== 'all') {
|
||||||
params.medicalType = [type.value]
|
params.medicalType = [type.value]
|
||||||
|
|||||||
@ -15,6 +15,8 @@ import useAccountStore from "@/store/account";
|
|||||||
const env = __VITE_ENV__;
|
const env = __VITE_ENV__;
|
||||||
const appid = env.MP_WX_APP_ID;
|
const appid = env.MP_WX_APP_ID;
|
||||||
const { account } = storeToRefs(useAccountStore());
|
const { account } = storeToRefs(useAccountStore());
|
||||||
|
const { login } = useAccountStore();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
@ -38,6 +40,7 @@ async function changeTeam({ teamId, corpId, corpUserId }) {
|
|||||||
teamId: team.value.teamId,
|
teamId: team.value.teamId,
|
||||||
corpUserId: corpUserId || ''
|
corpUserId: corpUserId || ''
|
||||||
});
|
});
|
||||||
|
await login()
|
||||||
if (account.value) {
|
if (account.value) {
|
||||||
bindTeam(corpUserId)
|
bindTeam(corpUserId)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -37,6 +37,13 @@ $primary-color: #0877F1;
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.patient-basic-info {
|
.patient-basic-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -84,6 +91,26 @@ $primary-color: #0877F1;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.remind-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 8rpx 20rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
border: 2rpx solid #3876f6;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remind-btn:active {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remind-btn-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #3876f6;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
.badge-processing {
|
.badge-processing {
|
||||||
background: #d1ecf1;
|
background: #d1ecf1;
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
<view class="article-title">{{ getArticleData(message).title }}</view>
|
<view class="article-title">{{ getArticleData(message).title }}</view>
|
||||||
<view class="article-desc">{{ getArticleData(message).desc }}</view>
|
<view class="article-desc">{{ getArticleData(message).desc }}</view>
|
||||||
</view>
|
</view>
|
||||||
<image v-if="getArticleData(message).imgUrl" class="article-image" :src="getArticleData(message).imgUrl"
|
<image v-if="getArticleData(message).cover" class="article-image" :src="getArticleData(message).cover"
|
||||||
mode="aspectFill" />
|
mode="aspectFill" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -77,7 +77,12 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
import api from "@/utils/api.js";
|
||||||
import { getParsedCustomMessage } from "@/utils/chat-utils.js";
|
import { getParsedCustomMessage } from "@/utils/chat-utils.js";
|
||||||
|
import { toast } from '@/utils/widget'
|
||||||
|
import useAccountStore from "@/store/account.js";
|
||||||
|
|
||||||
// import MessageCard from "./message-card/message-card.vue";
|
// import MessageCard from "./message-card/message-card.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -92,12 +97,22 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
defineEmits(["playVoice", "previewImage", "viewDetail"]);
|
defineEmits(["playVoice", "previewImage", "viewDetail"]);
|
||||||
|
const { account, openid } = storeToRefs(useAccountStore());
|
||||||
|
|
||||||
// 计算当前语音是否正在播放
|
// 计算当前语音是否正在播放
|
||||||
const isPlaying = computed(() => {
|
const isPlaying = computed(() => {
|
||||||
return props.playingVoiceId === props.message.ID;
|
return props.playingVoiceId === props.message.ID;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const payloadData = computed(() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(props.message.payload.data);
|
||||||
|
} catch (e) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
// 计算图片样式
|
// 计算图片样式
|
||||||
const getImageStyle = (imageInfo) => {
|
const getImageStyle = (imageInfo) => {
|
||||||
// 如果没有尺寸信息,使用默认样式
|
// 如果没有尺寸信息,使用默认样式
|
||||||
@ -195,6 +210,23 @@ const getArticleData = (message) => {
|
|||||||
|
|
||||||
// 处理文章点击
|
// 处理文章点击
|
||||||
const handleArticleClick = (message) => {
|
const handleArticleClick = (message) => {
|
||||||
|
if (isWechatChannels()) {
|
||||||
|
uni.openChannelsActivity({
|
||||||
|
finderUserName: payloadData.value.wechatChannels.finderUserName,
|
||||||
|
feedId: payloadData.value.wechatChannels.feedId,
|
||||||
|
success: () => {
|
||||||
|
markArticleRead(payloadData.value.sendId, payloadData.value.articleId);
|
||||||
|
},
|
||||||
|
fail: err => {
|
||||||
|
const errMsg = err.errMsg || '';
|
||||||
|
if (/cancel/i.test(errMsg)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toast(`打开视频号失败:${errMsg}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
const { articleId, sendId } = getArticleData(message);
|
const { articleId, sendId } = getArticleData(message);
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/article/article-detail?id=${articleId}&sendId=${sendId || ''}&corpId=${props.corpId}`,
|
url: `/pages/article/article-detail?id=${articleId}&sendId=${sendId || ''}&corpId=${props.corpId}`,
|
||||||
@ -244,6 +276,25 @@ const handleSurveyClick = (message) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isWechatChannels() {
|
||||||
|
const wechatChannels = payloadData.value.wechatChannels || {};
|
||||||
|
return typeof wechatChannels.finderUserName === 'string' && wechatChannels.finderUserName.trim() && typeof wechatChannels.feedId === 'string' && wechatChannels.feedId.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function markArticleRead(sendId, articleId) {
|
||||||
|
const unionid = account.value?.unionid;
|
||||||
|
if (!unionid || !articleId) return;
|
||||||
|
try {
|
||||||
|
const { success } = await api(
|
||||||
|
"addArticleReadRecord",
|
||||||
|
{ corpId: props.corpId, articleId, unionid, sendId },
|
||||||
|
false
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("markArticleRead failed:", err?.message || err);
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@ -1,41 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<page-meta
|
<page-meta :page-style="'overflow:' + (keyboardHeight > 0 ? 'hidden' : 'visible')"></page-meta>
|
||||||
:page-style="'overflow:' + (keyboardHeight > 0 ? 'hidden' : 'visible')"
|
|
||||||
></page-meta>
|
|
||||||
<view class="chat-page" :style="{ paddingBottom: keyboardHeight + 'px' }">
|
<view class="chat-page" :style="{ paddingBottom: keyboardHeight + 'px' }">
|
||||||
<!-- 患者信息栏 -->
|
<!-- 患者信息栏 -->
|
||||||
<view class="patient-info-bar" v-if="patientInfo.name">
|
<view class="patient-info-bar" v-if="patientInfo.name">
|
||||||
<view class="patient-info-content">
|
<view class="patient-info-content">
|
||||||
<view class="patient-basic-info">
|
<view class="patient-basic-info">
|
||||||
<text class="patient-name">{{ patientInfo.name }}</text>
|
<text class="patient-name">{{ patientInfo.name }}</text>
|
||||||
<text class="patient-detail"
|
<text class="patient-detail">{{ patientInfo.sex }} · {{ patientInfo.age }}岁</text>
|
||||||
>{{ patientInfo.sex }} · {{ patientInfo.age }}岁</text
|
|
||||||
>
|
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view class="header-actions">
|
||||||
class="status-badge"
|
<view class="status-badge" :class="chatStatusInfo.badgeClass" v-if="chatStatusInfo.badgeText">
|
||||||
:class="chatStatusInfo.badgeClass"
|
|
||||||
v-if="chatStatusInfo.badgeText"
|
|
||||||
>
|
|
||||||
<text class="badge-text">{{ chatStatusInfo.badgeText }}</text>
|
<text class="badge-text">{{ chatStatusInfo.badgeText }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view v-if="showSubscribeEntry" class="remind-btn" @click="handleSubscribeReminder">
|
||||||
|
<text class="remind-btn-text">接收提醒</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 聊天消息区域 -->
|
<!-- 聊天消息区域 -->
|
||||||
<scroll-view
|
<scroll-view class="chat-content" :style="{
|
||||||
class="chat-content"
|
|
||||||
:style="{
|
|
||||||
bottom: (keyboardHeight > 0 ? keyboardHeight + 60 : 60) + 'px',
|
bottom: (keyboardHeight > 0 ? keyboardHeight + 60 : 60) + 'px',
|
||||||
}"
|
}" scroll-y="true" enhanced="true" bounces="false" :scroll-into-view="scrollIntoView" @scroll="onScroll"
|
||||||
scroll-y="true"
|
@scrolltoupper="handleScrollToUpper" ref="chatScrollView">
|
||||||
enhanced="true"
|
|
||||||
bounces="false"
|
|
||||||
:scroll-into-view="scrollIntoView"
|
|
||||||
@scroll="onScroll"
|
|
||||||
@scrolltoupper="handleScrollToUpper"
|
|
||||||
ref="chatScrollView"
|
|
||||||
>
|
|
||||||
<!-- 加载更多提示 -->
|
<!-- 加载更多提示 -->
|
||||||
<view class="load-more-tip" v-if="messageList.length >= 15">
|
<view class="load-more-tip" v-if="messageList.length >= 15">
|
||||||
<view class="loading" v-if="isLoadingMore">
|
<view class="loading" v-if="isLoadingMore">
|
||||||
@ -51,21 +39,13 @@
|
|||||||
|
|
||||||
<!-- 聊天消息列表 -->
|
<!-- 聊天消息列表 -->
|
||||||
<view class="message-list" @click="closeMorePanel">
|
<view class="message-list" @click="closeMorePanel">
|
||||||
<view
|
<view v-for="(message, index) in messageList" :key="message.ID" :id="`msg-${message.ID}`" class="message-item"
|
||||||
v-for="(message, index) in messageList"
|
|
||||||
:key="message.ID"
|
|
||||||
:id="`msg-${message.ID}`"
|
|
||||||
class="message-item"
|
|
||||||
:class="{
|
:class="{
|
||||||
'message-right': message.flow === 'out',
|
'message-right': message.flow === 'out',
|
||||||
'message-left': message.flow === 'in',
|
'message-left': message.flow === 'in',
|
||||||
}"
|
}">
|
||||||
>
|
|
||||||
<!-- 时间分割线 -->
|
<!-- 时间分割线 -->
|
||||||
<view
|
<view v-if="shouldShowTime(message, index, messageList)" class="time-divider">
|
||||||
v-if="shouldShowTime(message, index, messageList)"
|
|
||||||
class="time-divider"
|
|
||||||
>
|
|
||||||
<text class="time-text">{{ formatTime(message.lastTime) }}</text>
|
<text class="time-text">{{ formatTime(message.lastTime) }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -76,31 +56,20 @@
|
|||||||
<!-- 消息内容 -->
|
<!-- 消息内容 -->
|
||||||
<view v-else class="message-content">
|
<view v-else class="message-content">
|
||||||
<!-- 发送者头像(统一处理) -->
|
<!-- 发送者头像(统一处理) -->
|
||||||
<image
|
<image v-if="message.flow === 'in'" class="doctor-msg-avatar" :src="getUserAvatar(message.from)"
|
||||||
v-if="message.flow === 'in'"
|
mode="aspectFill" />
|
||||||
class="doctor-msg-avatar"
|
|
||||||
:src="getUserAvatar(message.from)"
|
|
||||||
mode="aspectFill"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 发送者头像(统一处理) -->
|
<!-- 发送者头像(统一处理) -->
|
||||||
<image
|
<image v-if="message.flow === 'out'" class="user-msg-avatar" :src="getUserAvatar(message.from)"
|
||||||
v-if="message.flow === 'out'"
|
mode="aspectFill" />
|
||||||
class="user-msg-avatar"
|
|
||||||
:src="getUserAvatar(message.from)"
|
|
||||||
mode="aspectFill"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 消息内容区域 -->
|
<!-- 消息内容区域 -->
|
||||||
<view class="message-bubble-container">
|
<view class="message-bubble-container">
|
||||||
<!-- 用户名显示 -->
|
<!-- 用户名显示 -->
|
||||||
<view
|
<view class="username-label" :class="{
|
||||||
class="username-label"
|
|
||||||
:class="{
|
|
||||||
left: message.flow === 'in',
|
left: message.flow === 'in',
|
||||||
right: message.flow === 'out',
|
right: message.flow === 'out',
|
||||||
}"
|
}">
|
||||||
>
|
|
||||||
<text class="username-text">{{
|
<text class="username-text">{{
|
||||||
chatMember[message.from]?.name
|
chatMember[message.from]?.name
|
||||||
}}</text>
|
}}</text>
|
||||||
@ -108,25 +77,15 @@
|
|||||||
|
|
||||||
<view class="message-bubble" :class="getBubbleClass(message)">
|
<view class="message-bubble" :class="getBubbleClass(message)">
|
||||||
<!-- 消息内容 -->
|
<!-- 消息内容 -->
|
||||||
<MessageTypes
|
<MessageTypes :corpId="corpId" :message="message" :formatTime="formatTime"
|
||||||
:corpId="corpId"
|
:playingVoiceId="playingVoiceId" @playVoice="playVoice" @previewImage="previewImage"
|
||||||
:message="message"
|
@viewDetail="(message) => handleViewDetail(message)" />
|
||||||
:formatTime="formatTime"
|
|
||||||
:playingVoiceId="playingVoiceId"
|
|
||||||
@playVoice="playVoice"
|
|
||||||
@previewImage="previewImage"
|
|
||||||
@viewDetail="(message) => handleViewDetail(message)"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 发送状态 -->
|
<!-- 发送状态 -->
|
||||||
<view v-if="message.flow === 'out'" class="message-status">
|
<view v-if="message.flow === 'out'" class="message-status">
|
||||||
<text
|
<text v-if="message.status === 'failed'" class="status-text failed">发送失败</text>
|
||||||
v-if="message.status === 'failed'"
|
|
||||||
class="status-text failed"
|
|
||||||
>发送失败</text
|
|
||||||
>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -140,22 +99,12 @@
|
|||||||
<ConsultApply v-if="showConsultApply" @apply="handleApplyConsult" />
|
<ConsultApply v-if="showConsultApply" @apply="handleApplyConsult" />
|
||||||
|
|
||||||
<!-- 聊天输入组件 -->
|
<!-- 聊天输入组件 -->
|
||||||
<ChatInput
|
<ChatInput v-if="!isEvaluationPopupOpen && !showConsultCancel && !showConsultApply" ref="chatInputRef"
|
||||||
v-if="!isEvaluationPopupOpen && !showConsultCancel && !showConsultApply"
|
:timChatManager="timChatManager" :formatTime="formatTime" :groupId="chatInfo.conversationID
|
||||||
ref="chatInputRef"
|
|
||||||
:timChatManager="timChatManager"
|
|
||||||
:formatTime="formatTime"
|
|
||||||
:groupId="
|
|
||||||
chatInfo.conversationID
|
|
||||||
? chatInfo.conversationID.replace('GROUP', '')
|
? chatInfo.conversationID.replace('GROUP', '')
|
||||||
: ''
|
: ''
|
||||||
"
|
" :userId="openid" :corpId="corpId.value" :keyboardHeight="keyboardHeight"
|
||||||
:userId="openid"
|
@scrollToBottom="() => scrollToBottom(true)" @messageSent="() => scrollToBottom(true)" />
|
||||||
:corpId="corpId.value"
|
|
||||||
:keyboardHeight="keyboardHeight"
|
|
||||||
@scrollToBottom="() => scrollToBottom(true)"
|
|
||||||
@messageSent="() => scrollToBottom(true)"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -190,18 +139,28 @@ import ChatInput from "./components/chat-input.vue";
|
|||||||
import SystemMessage from "./components/system-message.vue";
|
import SystemMessage from "./components/system-message.vue";
|
||||||
import ConsultCancel from "./components/consult-cancel.vue";
|
import ConsultCancel from "./components/consult-cancel.vue";
|
||||||
import ConsultApply from "./components/consult-apply.vue";
|
import ConsultApply from "./components/consult-apply.vue";
|
||||||
|
import {
|
||||||
|
checkConversationSubscribeEntryVisible,
|
||||||
|
requestConversationSubscribeMessage,
|
||||||
|
} from "@/utils/subscribe-message";
|
||||||
|
import {
|
||||||
|
SUBSCRIBE_MESSAGE_ROLE,
|
||||||
|
SUBSCRIBE_MESSAGE_SCENE,
|
||||||
|
} from "@/utils/subscribe-message-config";
|
||||||
|
|
||||||
const timChatManager = globalTimChatManager;
|
const timChatManager = globalTimChatManager;
|
||||||
|
|
||||||
// corpId 从群组信息中获取
|
// corpId 从群组信息中获取
|
||||||
const corpId = ref("");
|
const corpId = ref("");
|
||||||
|
const showSubscribeEntry = ref(false);
|
||||||
|
|
||||||
// 获取登录状态
|
// 获取登录状态
|
||||||
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
|
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
|
||||||
const { initIMAfterLogin } = useAccountStore();
|
const { initIMAfterLogin, login } = useAccountStore();
|
||||||
|
|
||||||
// 聊天输入组件引用
|
// 聊天输入组件引用
|
||||||
const chatInputRef = ref(null);
|
const chatInputRef = ref(null);
|
||||||
|
const loginPromise = ref(null);
|
||||||
|
|
||||||
const groupId = ref("");
|
const groupId = ref("");
|
||||||
const { chatMember, getGroupInfo, getUserAvatar } = useGroupChat(groupId);
|
const { chatMember, getGroupInfo, getUserAvatar } = useGroupChat(groupId);
|
||||||
@ -445,7 +404,10 @@ function getBubbleClass(message) {
|
|||||||
|
|
||||||
// 页面加载
|
// 页面加载
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
groupId.value = options.groupID || "";
|
loginPromise.value = login();
|
||||||
|
await loginPromise.value;
|
||||||
|
loginPromise.value = null;
|
||||||
|
groupId.value = decodeURIComponent(options.groupID) || "";
|
||||||
messageList.value = [];
|
messageList.value = [];
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
if (options.conversationID) {
|
if (options.conversationID) {
|
||||||
@ -856,7 +818,12 @@ const handleScrollToUpper = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 页面显示
|
// 页面显示
|
||||||
onShow(() => {
|
onShow(async () => {
|
||||||
|
if (loginPromise.value) {
|
||||||
|
await loginPromise.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSubscribeEntryState();
|
||||||
if (!account.value || !openid.value) {
|
if (!account.value || !openid.value) {
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
url: "/pages/login/login",
|
url: "/pages/login/login",
|
||||||
@ -908,6 +875,14 @@ onShow(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => corpId.value,
|
||||||
|
() => {
|
||||||
|
loadSubscribeEntryState();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
// 页面隐藏
|
// 页面隐藏
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
stopIMMonitoring();
|
stopIMMonitoring();
|
||||||
@ -1063,6 +1038,31 @@ const handleApplyConsult = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSubscribeReminder = async () => {
|
||||||
|
await requestConversationSubscribeMessage({
|
||||||
|
role: SUBSCRIBE_MESSAGE_ROLE.PATIENT,
|
||||||
|
scene: SUBSCRIBE_MESSAGE_SCENE.CHAT,
|
||||||
|
conversationId: chatInfo.value.conversationID || "",
|
||||||
|
groupId: groupId.value || "",
|
||||||
|
corpId: corpId.value || "",
|
||||||
|
patientId: patientId.value || "",
|
||||||
|
userId: openid.value || account.value?.openid || "",
|
||||||
|
openid: openid.value || account.value?.openid || "",
|
||||||
|
unionid: account.value?.unionid || "",
|
||||||
|
extraData: {
|
||||||
|
orderStatus: orderStatus.value || "",
|
||||||
|
page: "pages/message/index",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadSubscribeEntryState = async () => {
|
||||||
|
showSubscribeEntry.value = await checkConversationSubscribeEntryVisible(
|
||||||
|
corpId.value || "",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// 页面卸载
|
// 页面卸载
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
clearMessageCache();
|
clearMessageCache();
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="message-page">
|
<view class="message-page">
|
||||||
|
|
||||||
<!-- 消息列表 -->
|
<!-- 消息列表 -->
|
||||||
<scroll-view class="message-list" scroll-y="true" refresher-enabled :refresher-triggered="refreshing"
|
<scroll-view class="message-list" scroll-y="true" refresher-enabled :refresher-triggered="refreshing"
|
||||||
@refresherrefresh="handleRefresh" @scrolltolower="handleLoadMore">
|
@refresherrefresh="handleRefresh" @scrolltolower="handleLoadMore">
|
||||||
@ -52,6 +51,14 @@
|
|||||||
}}</text>
|
}}</text>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
|
<view
|
||||||
|
v-if="showSubscribeEntry"
|
||||||
|
class="subscribe-entry"
|
||||||
|
@click="handleSubscribeReminder"
|
||||||
|
>
|
||||||
|
<text class="subscribe-entry-text">接收提醒</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -65,9 +72,19 @@ import { mergeConversationWithGroupDetails } from "@/utils/conversation-merger.j
|
|||||||
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
|
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
|
||||||
import useGroupAvatars from "./hooks/use-group-avatars.js";
|
import useGroupAvatars from "./hooks/use-group-avatars.js";
|
||||||
import GroupAvatar from "@/components/group-avatar.vue";
|
import GroupAvatar from "@/components/group-avatar.vue";
|
||||||
|
import {
|
||||||
|
checkConversationSubscribeEntryVisible,
|
||||||
|
requestConversationSubscribeMessage,
|
||||||
|
} from "@/utils/subscribe-message";
|
||||||
|
import {
|
||||||
|
SUBSCRIBE_MESSAGE_ROLE,
|
||||||
|
SUBSCRIBE_MESSAGE_SCENE,
|
||||||
|
} from "@/utils/subscribe-message-config";
|
||||||
|
|
||||||
// 获取登录状态
|
// 获取登录状态
|
||||||
const { account, openid, isIMInitialized, hasImCorpId } = storeToRefs(useAccountStore());
|
const { account, openid, isIMInitialized, hasImCorpId, teams } = storeToRefs(
|
||||||
|
useAccountStore()
|
||||||
|
);
|
||||||
const { initIMAfterLogin } = useAccountStore();
|
const { initIMAfterLogin } = useAccountStore();
|
||||||
|
|
||||||
// 状态
|
// 状态
|
||||||
@ -76,6 +93,7 @@ const loading = ref(false);
|
|||||||
const loadingMore = ref(false);
|
const loadingMore = ref(false);
|
||||||
const hasMore = ref(false);
|
const hasMore = ref(false);
|
||||||
const refreshing = ref(false);
|
const refreshing = ref(false);
|
||||||
|
const showSubscribeEntry = ref(false);
|
||||||
|
|
||||||
// 群聊头像管理
|
// 群聊头像管理
|
||||||
const { loadGroupAvatars, getAvatarList } = useGroupAvatars();
|
const { loadGroupAvatars, getAvatarList } = useGroupAvatars();
|
||||||
@ -492,14 +510,45 @@ const cleanMessageText = (text) => {
|
|||||||
return text.replace(/[\r\n]+/g, " ").trim();
|
return text.replace(/[\r\n]+/g, " ").trim();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSubscribeReminder = async () => {
|
||||||
|
await requestConversationSubscribeMessage({
|
||||||
|
role: SUBSCRIBE_MESSAGE_ROLE.PATIENT,
|
||||||
|
scene: SUBSCRIBE_MESSAGE_SCENE.LIST,
|
||||||
|
corpId: teams.value.find((item) => item?.corpId)?.corpId || "",
|
||||||
|
userId: openid.value || account.value?.openid || "",
|
||||||
|
openid: openid.value || account.value?.openid || "",
|
||||||
|
unionid: account.value?.unionid || "",
|
||||||
|
extraData: {
|
||||||
|
page: "pages/message/message",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadSubscribeEntryState = async () => {
|
||||||
|
const currentCorpId = teams.value.find((item) => item?.corpId)?.corpId || "";
|
||||||
|
showSubscribeEntry.value = await checkConversationSubscribeEntryVisible(
|
||||||
|
currentCorpId,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// 页面显示
|
// 页面显示
|
||||||
onShow(async () => {
|
onShow(async () => {
|
||||||
// 页面显示时刷新 tabBar 徽章
|
// 页面显示时刷新 tabBar 徽章
|
||||||
// if (globalUnreadListenerManager.isInitialized) {
|
// if (globalUnreadListenerManager.isInitialized) {
|
||||||
// await globalUnreadListenerManager.refreshBadge();
|
// await globalUnreadListenerManager.refreshBadge();
|
||||||
// }
|
// }
|
||||||
|
await loadSubscribeEntryState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => teams.value.map((item) => item?.corpId).join(","),
|
||||||
|
() => {
|
||||||
|
loadSubscribeEntryState();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
// 页面隐藏
|
// 页面隐藏
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
console.log("【消息列表页】页面隐藏");
|
console.log("【消息列表页】页面隐藏");
|
||||||
@ -718,4 +767,32 @@ onUnmounted(() => {
|
|||||||
color: #999;
|
color: #999;
|
||||||
padding-bottom: 10rpx;
|
padding-bottom: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subscribe-entry {
|
||||||
|
position: fixed;
|
||||||
|
right: 32rpx;
|
||||||
|
bottom: 180rpx;
|
||||||
|
width: 116rpx;
|
||||||
|
height: 116rpx;
|
||||||
|
border-radius: 58rpx;
|
||||||
|
background: #fff;
|
||||||
|
border: 2rpx solid #3876f6;
|
||||||
|
box-shadow: 0 8rpx 24rpx rgba(56, 118, 246, 0.16);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-entry:active {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribe-entry-text {
|
||||||
|
width: 56rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: #3876f6;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -56,10 +56,12 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="list.length === 1"
|
<view v-if="list.length === 1" class="py-12 px-15">
|
||||||
class="flex-shrink-0 mx-10 py-12 leading-normal text-white text-center rounded bg-primary" @click="submit()">
|
<view class="flex-shrink-0 py-10 text-white text-center rounded-full bg-primary" @click="submit()">
|
||||||
提交
|
提交
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="h-full flex flex-col">
|
<view class="h-full flex flex-col">
|
||||||
<view class="flex-shrink-0 px-10 pt-5 text-base font-semibold text-center truncate">{{ surery.name }}</view>
|
<view class="flex-shrink-0 px-10 pt-5 text-base font-semibold text-center truncate">{{ survey.name }}</view>
|
||||||
<view v-if="surery.description"
|
<view v-if="survey.description"
|
||||||
class="flex-shrink-0 px-10 mt-10 text-sm leading-normal text-gray line-clamp-2 text-center">
|
class="flex-shrink-0 px-10 mt-10 text-sm leading-normal text-gray line-clamp-2 text-center">
|
||||||
{{ surery.description }}
|
{{ survey.description }}
|
||||||
</view>
|
</view>
|
||||||
<view class="flex items-center text-gray text-sm px-10 mt-10">
|
<view class="flex items-center text-gray text-sm px-10 mt-10">
|
||||||
<view v-if="surery.enableScore">
|
<view v-if="survey.enableScore">
|
||||||
当前得分:<text class="text-primary text-base font-semibold min-w-5 inline-block">{{ allScore }}
|
当前得分:<text class="text-primary text-base font-semibold min-w-5 inline-block">{{ allScore }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<view class="flex-grow pl-4 text-gray leading-normal"
|
<view class="flex-grow pl-4 text-gray leading-normal"
|
||||||
:class="quesiton.value && quesiton.value === opt.value ? 'text-primary' : ''">
|
:class="quesiton.value && quesiton.value === opt.value ? 'text-primary' : ''">
|
||||||
{{ opt.label }}
|
{{ opt.label }}
|
||||||
<text v-if="surery.enableScore && opt.score >= 0">
|
<text v-if="survey.enableScore && opt.score >= 0">
|
||||||
( {{ opt.score }}分)
|
( {{ opt.score }}分)
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
@ -52,7 +52,7 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
customerName: { type: String, default: '' },
|
customerName: { type: String, default: '' },
|
||||||
list: { type: Array, default: () => ([]) },
|
list: { type: Array, default: () => ([]) },
|
||||||
surery: { type: Object, default: () => ({}) }
|
survey: { type: Object, default: () => ({}) }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
allScore() {
|
allScore() {
|
||||||
@ -66,6 +66,12 @@ export default {
|
|||||||
return score
|
return score
|
||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
logScore() {
|
||||||
|
console.log(this.survey)
|
||||||
|
console.log(this.allScore)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
1
static/pdf.svg
Normal file
1
static/pdf.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg t="1713431721970" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1534" width="200" height="200"><path d="M910.2336 1024H113.7664C51.2 1024 0 972.8 0 910.2336V113.7664C0 51.2 51.2 0 113.7664 0h796.4672C972.8 0 1024 51.2 1024 113.7664v796.4672C1024 972.8 972.8 1024 910.2336 1024zM155.2128 555.4432h44.672c35.9936 1.2032 66.0224-8.704 89.984-29.6704 24.0128-20.9664 36.0192-48.3328 36.0192-82.1248 0-33.28-10.24-58.9568-30.7712-76.8768-20.5312-17.92-49.3568-26.88-86.5536-26.88h-97.792v344.2432h44.4416v-128.6912z m0-176.4352h45.3376c52.48 0 78.6688 22.1184 78.6688 66.432 0 22.8096-7.04 40.3456-21.12 52.5824-14.08 12.1856-34.6624 18.304-61.7728 18.304H155.2128v-137.3184z m234.0352 305.1008h94.6432c54.528 0 99.072-16.0768 133.6576-48.2048 34.6112-32.1536 51.8912-74.9056 51.8912-128.256 0-51.0976-17.28-91.8528-51.8912-122.2144-34.56-30.336-77.952-45.568-130.0992-45.568h-98.2016v344.2432z m44.416-304.6656h51.9936c41.0624 0 74.1632 10.8032 99.328 32.4608 25.216 21.6064 37.7856 53.888 37.7856 96.8704 0 43.008-12.2368 76.3392-36.7872 100.224-24.5248 23.8592-58.624 35.7632-102.3232 35.7632H433.664V379.4432z m479.5648 0v-39.5776h-177.3312v344.2432h44.4416v-150.4512h123.1104V494.592h-123.136v-115.1232h132.9152z" fill="#D93838" p-id="1535"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@ -14,11 +14,20 @@ export default defineStore("accountStore", () => {
|
|||||||
const openid = ref("");
|
const openid = ref("");
|
||||||
const externalUserId = ref('');
|
const externalUserId = ref('');
|
||||||
const teams = ref([]);
|
const teams = ref([]);
|
||||||
const hasImCorpId = computed(() => teams.value.some(i => i.corpId === 'wpLgjyawAA8N0gWmXgyJq8wpjGcOT7fg'));
|
const hasImCorpId = computed(() => {
|
||||||
|
// 正式环境IM账号优先 暂时只有wpLgjyawAA8N0gWmXgyJq8wpjGcOT7fg机构的才开启IM账号
|
||||||
|
if (env.MP_VERIFY_IM_CORP_ID === 'YES') {
|
||||||
|
return teams.value.some(i => i.corpId === 'wpLgjyawAA8N0gWmXgyJq8wpjGcOT7fg')
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
});
|
||||||
const teamsPromise = ref(null);
|
const teamsPromise = ref(null);
|
||||||
|
|
||||||
async function login(phoneCode = '') {
|
async function login(phoneCode = '') {
|
||||||
if (loading.value) return;
|
if (loading.value) return;
|
||||||
|
if (account.value && account.value.mobile) {
|
||||||
|
return account.value
|
||||||
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const { code } = await uni.login({
|
const { code } = await uni.login({
|
||||||
|
|||||||
@ -72,7 +72,10 @@ const urlsConfig = {
|
|||||||
getGroupListByGroupId: "getGroupListByGroupId",
|
getGroupListByGroupId: "getGroupListByGroupId",
|
||||||
createConsultGroup: "createConsultGroup",
|
createConsultGroup: "createConsultGroup",
|
||||||
cancelConsultApplication: "cancelConsultApplication",
|
cancelConsultApplication: "cancelConsultApplication",
|
||||||
getGroupList: "getGroupList"
|
getGroupList: "getGroupList",
|
||||||
|
getConversationSubscribeConfig: "getConversationSubscribeConfig",
|
||||||
|
saveConversationSubscribeResult: "saveConversationSubscribeResult",
|
||||||
|
sendConversationSubscribeEvent: "sendConversationSubscribeEvent"
|
||||||
},
|
},
|
||||||
survery: {
|
survery: {
|
||||||
getMiniAppReceivedSurveryList: 'getMiniAppReceivedSurveryList',
|
getMiniAppReceivedSurveryList: 'getMiniAppReceivedSurveryList',
|
||||||
|
|||||||
64
utils/subscribe-message-config.js
Normal file
64
utils/subscribe-message-config.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
const env = __VITE_ENV__;
|
||||||
|
|
||||||
|
export const SUBSCRIBE_MESSAGE_ROLE = {
|
||||||
|
PATIENT: "patient",
|
||||||
|
DOCTOR: "doctor",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SUBSCRIBE_MESSAGE_SCENE = {
|
||||||
|
DEFAULT: "default",
|
||||||
|
LIST: "list",
|
||||||
|
CHAT: "chat",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SUBSCRIBE_MESSAGE_EVENT = {
|
||||||
|
PATIENT_CONSULT_APPLY: "patient_consult_apply",
|
||||||
|
PATIENT_CHAT_MESSAGE: "patient_chat_message",
|
||||||
|
DOCTOR_ACCEPT: "doctor_accept",
|
||||||
|
DOCTOR_REJECT: "doctor_reject",
|
||||||
|
DOCTOR_CHAT_MESSAGE: "doctor_chat_message",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SUBSCRIBE_MESSAGE_TEMPLATES = {
|
||||||
|
consultationReply: {
|
||||||
|
code: "consultationReply",
|
||||||
|
role: SUBSCRIBE_MESSAGE_ROLE.PATIENT,
|
||||||
|
id:
|
||||||
|
env.MP_SUBSCRIBE_TEMPLATE_CONSULT_REPLY ||
|
||||||
|
"VF9AC-7Rr3E1drbxBCrxbC-rLTnidmlNXopKReSAd_w",
|
||||||
|
name: "咨询回复通知",
|
||||||
|
events: [
|
||||||
|
SUBSCRIBE_MESSAGE_EVENT.DOCTOR_ACCEPT,
|
||||||
|
SUBSCRIBE_MESSAGE_EVENT.DOCTOR_REJECT,
|
||||||
|
SUBSCRIBE_MESSAGE_EVENT.DOCTOR_CHAT_MESSAGE,
|
||||||
|
],
|
||||||
|
fields: ["患者姓名", "回复时间", "回复者", "所属机构"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SUBSCRIBE_MESSAGE_SCENE_TEMPLATE_MAP = {
|
||||||
|
[SUBSCRIBE_MESSAGE_ROLE.PATIENT]: {
|
||||||
|
[SUBSCRIBE_MESSAGE_SCENE.DEFAULT]: ["consultationReply"],
|
||||||
|
[SUBSCRIBE_MESSAGE_SCENE.LIST]: ["consultationReply"],
|
||||||
|
[SUBSCRIBE_MESSAGE_SCENE.CHAT]: ["consultationReply"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function resolveSubscribeTemplates({
|
||||||
|
role,
|
||||||
|
scene = SUBSCRIBE_MESSAGE_SCENE.DEFAULT,
|
||||||
|
} = {}) {
|
||||||
|
const roleMap = SUBSCRIBE_MESSAGE_SCENE_TEMPLATE_MAP[role] || {};
|
||||||
|
const keys =
|
||||||
|
roleMap[scene] || roleMap[SUBSCRIBE_MESSAGE_SCENE.DEFAULT] || [];
|
||||||
|
const seen = new Set();
|
||||||
|
|
||||||
|
return keys
|
||||||
|
.map((key) => SUBSCRIBE_MESSAGE_TEMPLATES[key])
|
||||||
|
.filter((item) => item && item.id)
|
||||||
|
.filter((item) => {
|
||||||
|
if (seen.has(item.id)) return false;
|
||||||
|
seen.add(item.id);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
222
utils/subscribe-message.js
Normal file
222
utils/subscribe-message.js
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
import api from "@/utils/api";
|
||||||
|
import { toast } from "@/utils/widget";
|
||||||
|
import { resolveSubscribeTemplates } from "./subscribe-message-config";
|
||||||
|
|
||||||
|
const SUBSCRIBE_ACCEPT_STATUS = "accept";
|
||||||
|
const SUBSCRIBE_REJECT_STATUS = "reject";
|
||||||
|
const SUBSCRIBE_BAN_STATUS = "ban";
|
||||||
|
const SUBSCRIBE_FILTER_STATUS = "filter";
|
||||||
|
const SUBSCRIBE_CANCEL_STATUS = "cancel";
|
||||||
|
const SUBSCRIBE_FAILED_STATUS = "failed";
|
||||||
|
const subscribeDisplayConfigCache = new Map();
|
||||||
|
|
||||||
|
function canUseSubscribeMessage() {
|
||||||
|
return (
|
||||||
|
typeof wx !== "undefined" &&
|
||||||
|
typeof wx.requestSubscribeMessage === "function"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestSubscribeMessage(tmplIds = []) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
wx.requestSubscribeMessage({
|
||||||
|
tmplIds,
|
||||||
|
success(res) {
|
||||||
|
resolve({ ok: true, res });
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
resolve({ ok: false, err });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeFailStatus(err = {}) {
|
||||||
|
const errCode = Number(err.errCode || 0);
|
||||||
|
const errMsg = String(err.errMsg || "").toLowerCase();
|
||||||
|
|
||||||
|
if (errCode === 20004 || errMsg.includes("main switch")) {
|
||||||
|
return SUBSCRIBE_BAN_STATUS;
|
||||||
|
}
|
||||||
|
if (errCode === 20005 || errMsg.includes("ban")) {
|
||||||
|
return SUBSCRIBE_BAN_STATUS;
|
||||||
|
}
|
||||||
|
if (errMsg.includes("filter")) {
|
||||||
|
return SUBSCRIBE_FILTER_STATUS;
|
||||||
|
}
|
||||||
|
if (errMsg.includes("cancel")) {
|
||||||
|
return SUBSCRIBE_CANCEL_STATUS;
|
||||||
|
}
|
||||||
|
return SUBSCRIBE_FAILED_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTemplateResultRecords(templates = [], requestResult = {}, context = {}) {
|
||||||
|
const requestedAt = Date.now();
|
||||||
|
|
||||||
|
if (requestResult.ok) {
|
||||||
|
const res = requestResult.res || {};
|
||||||
|
return templates.map((template) => ({
|
||||||
|
role: context.role || "",
|
||||||
|
scene: context.scene || "",
|
||||||
|
conversationId: context.conversationId || "",
|
||||||
|
groupId: context.groupId || "",
|
||||||
|
corpId: context.corpId || "",
|
||||||
|
teamId: context.teamId || "",
|
||||||
|
patientId: context.patientId || "",
|
||||||
|
doctorId: context.doctorId || "",
|
||||||
|
userId: context.userId || "",
|
||||||
|
openid: context.openid || "",
|
||||||
|
unionid: context.unionid || "",
|
||||||
|
templateId: template.id,
|
||||||
|
templateCode: template.code,
|
||||||
|
templateName: template.name,
|
||||||
|
eventTypes: template.events,
|
||||||
|
status: String(res[template.id] || SUBSCRIBE_FAILED_STATUS),
|
||||||
|
rawResult: res,
|
||||||
|
requestedAt,
|
||||||
|
extraData: context.extraData || {},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = normalizeFailStatus(requestResult.err);
|
||||||
|
return templates.map((template) => ({
|
||||||
|
role: context.role || "",
|
||||||
|
scene: context.scene || "",
|
||||||
|
conversationId: context.conversationId || "",
|
||||||
|
groupId: context.groupId || "",
|
||||||
|
corpId: context.corpId || "",
|
||||||
|
teamId: context.teamId || "",
|
||||||
|
patientId: context.patientId || "",
|
||||||
|
doctorId: context.doctorId || "",
|
||||||
|
userId: context.userId || "",
|
||||||
|
openid: context.openid || "",
|
||||||
|
unionid: context.unionid || "",
|
||||||
|
templateId: template.id,
|
||||||
|
templateCode: template.code,
|
||||||
|
templateName: template.name,
|
||||||
|
eventTypes: template.events,
|
||||||
|
status,
|
||||||
|
rawResult: requestResult.err || {},
|
||||||
|
requestedAt,
|
||||||
|
extraData: context.extraData || {},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildToastMessage(records = [], reportResult = { success: false }) {
|
||||||
|
const accepted = records.some((item) => item.status === SUBSCRIBE_ACCEPT_STATUS);
|
||||||
|
|
||||||
|
if (accepted && reportResult?.success === false) {
|
||||||
|
return reportResult?.message || "提醒开启失败,请稍后再试";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (records.some((item) => item.status === SUBSCRIBE_ACCEPT_STATUS)) {
|
||||||
|
return "会话消息提醒开启";
|
||||||
|
}
|
||||||
|
if (records.some((item) => item.status === SUBSCRIBE_BAN_STATUS)) {
|
||||||
|
return "请先在微信设置中开启订阅消息提醒";
|
||||||
|
}
|
||||||
|
if (records.some((item) => item.status === SUBSCRIBE_FILTER_STATUS)) {
|
||||||
|
return "当前提醒模板暂不可用";
|
||||||
|
}
|
||||||
|
if (records.some((item) => item.status === SUBSCRIBE_REJECT_STATUS)) {
|
||||||
|
return "你已拒绝本次提醒订阅";
|
||||||
|
}
|
||||||
|
if (records.some((item) => item.status === SUBSCRIBE_CANCEL_STATUS)) {
|
||||||
|
return "你已取消本次提醒订阅";
|
||||||
|
}
|
||||||
|
return "提醒订阅请求失败,请稍后再试";
|
||||||
|
}
|
||||||
|
|
||||||
|
async function reportSubscribeResult(records = []) {
|
||||||
|
if (!records.length) return { success: false };
|
||||||
|
try {
|
||||||
|
return await api(
|
||||||
|
"saveConversationSubscribeResult",
|
||||||
|
{
|
||||||
|
records,
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("保存订阅结果失败:", error);
|
||||||
|
return { success: false, message: error?.message || "保存失败" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function checkConversationSubscribeEntryVisible(
|
||||||
|
corpId = "",
|
||||||
|
forceRefresh = false
|
||||||
|
) {
|
||||||
|
const normalizedCorpId = String(corpId || "").trim();
|
||||||
|
if (!normalizedCorpId) return false;
|
||||||
|
|
||||||
|
if (!forceRefresh && subscribeDisplayConfigCache.has(normalizedCorpId)) {
|
||||||
|
return subscribeDisplayConfigCache.get(normalizedCorpId);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await api(
|
||||||
|
"getConversationSubscribeConfig",
|
||||||
|
{ corpId: normalizedCorpId },
|
||||||
|
false
|
||||||
|
);
|
||||||
|
const enabled = !!result?.data?.enabled;
|
||||||
|
subscribeDisplayConfigCache.set(normalizedCorpId, enabled);
|
||||||
|
return enabled;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取订阅提醒显示配置失败:", error);
|
||||||
|
subscribeDisplayConfigCache.set(normalizedCorpId, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function requestConversationSubscribeMessage(context = {}) {
|
||||||
|
const templates = resolveSubscribeTemplates({
|
||||||
|
role: context.role,
|
||||||
|
scene: context.scene,
|
||||||
|
});
|
||||||
|
const requestTemplates = templates.slice(0, 1);
|
||||||
|
|
||||||
|
if (!requestTemplates.length) {
|
||||||
|
await toast("暂未配置提醒模板");
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
code: "template_missing",
|
||||||
|
records: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canUseSubscribeMessage()) {
|
||||||
|
await toast("当前微信版本不支持订阅消息");
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
code: "unsupported",
|
||||||
|
records: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestResult = await requestSubscribeMessage(
|
||||||
|
requestTemplates.map((item) => item.id)
|
||||||
|
);
|
||||||
|
const records = buildTemplateResultRecords(
|
||||||
|
requestTemplates,
|
||||||
|
requestResult,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
const reportResult = await reportSubscribeResult(records);
|
||||||
|
await toast(buildToastMessage(records, reportResult));
|
||||||
|
|
||||||
|
const subscribeSuccess =
|
||||||
|
records.some((item) => item.status === SUBSCRIBE_ACCEPT_STATUS) &&
|
||||||
|
reportResult?.success !== false;
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: subscribeSuccess,
|
||||||
|
reportResult,
|
||||||
|
records,
|
||||||
|
acceptedTemplateIds: records
|
||||||
|
.filter((item) => item.status === SUBSCRIBE_ACCEPT_STATUS)
|
||||||
|
.map((item) => item.templateId),
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user