Merge branch 'dev-wdb' of http://175.27.226.205:3000/huxuejian/ykt-wxapp into dev-wdb
# Conflicts: # App.vue # pages.json
@ -1,4 +1,5 @@
|
||||
MP_API_BASE_URL=http://192.168.60.2:8080
|
||||
MP_CACHE_PREFIX=development
|
||||
MP_WX_APP_ID=wx93af55767423938e
|
||||
MP_CORP_ID=wwe3fb2faa52cf9dfb
|
||||
MP_TIM_SDK_APP_ID=1600072268
|
||||
|
||||
31
App.vue
@ -1,15 +1,11 @@
|
||||
<script>
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import {
|
||||
globalTimChatManager
|
||||
} from "@/utils/tim-chat.js";
|
||||
import { globalTimChatManager } from "@/utils/tim-chat.js";
|
||||
|
||||
export default {
|
||||
onLaunch: function () {
|
||||
// 需在 pinia 安装后再获取 store,避免 getActivePinia 报错
|
||||
const {
|
||||
login
|
||||
} = useAccountStore();
|
||||
const { login } = useAccountStore();
|
||||
login();
|
||||
console.log("App Launch: ");
|
||||
},
|
||||
@ -18,15 +14,16 @@
|
||||
},
|
||||
onHide: function () {
|
||||
console.log("App Hide");
|
||||
try {
|
||||
if (globalTimChatManager && globalTimChatManager.tim) {
|
||||
console.log('小程序退出,开始退出腾讯IM');
|
||||
globalTimChatManager.destroy();
|
||||
console.log('腾讯IM退出成功');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('退出腾讯IM失败:', error);
|
||||
}
|
||||
// 小程序退出时退出腾讯IM登录
|
||||
// try {
|
||||
// if (globalTimChatManager && globalTimChatManager.tim) {
|
||||
// console.log('小程序退出,开始退出腾讯IM');
|
||||
// globalTimChatManager.destroy();
|
||||
// console.log('腾讯IM退出成功');
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('退出腾讯IM失败:', error);
|
||||
// }
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -51,6 +48,9 @@
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
.absolute{
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
@ -156,7 +156,6 @@
|
||||
.pt-5 {
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
|
||||
.pt-15 {
|
||||
padding-top: 30rpx;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view v-if="showCancel || showConfirm" class="relative px-15 py-12 bg-white text-center"
|
||||
<view v-if="showCancel || showConfirm" class="relative flex px-15 py-12 bg-white text-center"
|
||||
:class="hidedenShadow ? '' : 'shadow-up'">
|
||||
<view v-if="showCancel" class="flex-grow py-10 text-base border-primary rounded text-primary rounded"
|
||||
@click="cancel()">
|
||||
|
||||
@ -49,9 +49,9 @@ const displayRange = computed(() => {
|
||||
}
|
||||
return props.range;
|
||||
})
|
||||
|
||||
const value = computed(() => {
|
||||
if (!props.form || !props.form[props.title]) return '';
|
||||
|
||||
const currentValue = props.form[props.title];
|
||||
// 如果range是对象数组,找到对应的label显示
|
||||
if (Array.isArray(props.range) && props.range.length > 0 && typeof props.range[0] === 'object') {
|
||||
@ -65,7 +65,7 @@ function change(e) {
|
||||
const selectedValue = props.range[e.detail.value];
|
||||
emits('change', {
|
||||
title: props.title,
|
||||
value: selectedValue
|
||||
value: typeof selectedValue === 'object' ? selectedValue.value : selectedValue
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -4,8 +4,9 @@
|
||||
{{ name }}<text v-if="required" class="form-cell--required"></text>
|
||||
</view>
|
||||
<view class="mt-10">
|
||||
<textarea :disabled="disableChange" :value="value" class="form-textarea" :placeholder="placeholder"
|
||||
placeholder-class="form__placeholder" :maxlength="wordLimit" @input="change($event)" />
|
||||
<textarea :disabled="disableChange" :value="value" class="form-textarea"
|
||||
:class="border ? 'form-textarea--border' : ''" :placeholder="placeholder" placeholder-class="form__placeholder"
|
||||
:maxlength="wordLimit" @input="change($event)" />
|
||||
<view v-if="wordLimit > 0" class="form-textarea__count">
|
||||
{{ value && value.length ? value.length : 0 }} / {{ wordLimit }}
|
||||
</view>
|
||||
@ -17,6 +18,10 @@ import { computed } from 'vue';
|
||||
|
||||
const emits = defineEmits(['change']);
|
||||
const props = defineProps({
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
form: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
@ -45,7 +50,7 @@ const placeholder = computed(() => `请输入${props.name || ''}`)
|
||||
const value = computed(() => props.form && props.form && props.form[props.title] ? props.form[props.title] : '')
|
||||
const wordLimit = computed(() => {
|
||||
if (typeof props.wordLimit === 'string' && Number(props.wordLimit) > 0) {
|
||||
return Number.ceil(props.wordLimit)
|
||||
return Math.ceil(props.wordLimit)
|
||||
}
|
||||
if (typeof props.wordLimit === 'number' && props.wordLimit > 0) {
|
||||
return props.wordLimit
|
||||
@ -72,12 +77,15 @@ function change(e) {
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
font-size: 28rpx;
|
||||
border: 1px solid #eee;
|
||||
padding: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-textarea--border {
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
.form-textarea__count {
|
||||
padding-top: 20rpx;
|
||||
text-align: right;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<view class="full-page" :style="pageStyle">
|
||||
<view class="full-page" :class="pageClass" :style="pageStyle">
|
||||
<view v-if="hasHeader" class="page-header">
|
||||
<slot name="header"></slot>
|
||||
</view>
|
||||
<view class="page-main" :style="mainStyle">
|
||||
<view class="page-main" :class="mainClass" :style="mainStyle">
|
||||
<view v-if="customScroll" class="page-scroll">
|
||||
<slot></slot>
|
||||
</view>
|
||||
@ -16,7 +16,7 @@
|
||||
<slot name="footer"></slot>
|
||||
</view>
|
||||
<!-- #ifdef MP-->
|
||||
<view class="safeareaBottom"></view>
|
||||
<view v-if="showSafeArea" class="safeareaBottom"></view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
@ -27,8 +27,11 @@ import useDebounce from '@/utils/useDebounce';
|
||||
const emits = defineEmits(['reachBottom']);
|
||||
const props = defineProps({
|
||||
customScroll: { type: Boolean, default: false },
|
||||
mainClass: { type: String, default: '' },
|
||||
mainStyle: { default: '' },
|
||||
pageStyle: { default: '' }
|
||||
pageClass: { type: String, default: '' },
|
||||
pageStyle: { default: '' },
|
||||
showSafeArea: { type: Boolean, default: true }
|
||||
});
|
||||
const slots = useSlots();
|
||||
const hasHeader = computed(() => !!slots.header);
|
||||
|
||||
@ -39,8 +39,10 @@ export default function useGuard() {
|
||||
|
||||
async function triggleShowEvents() {
|
||||
await promise;
|
||||
if (account.value && account.value.openid) {
|
||||
onShowEvents.value.forEach(fn => fn(onShowOptions.value))
|
||||
}
|
||||
}
|
||||
|
||||
function useShow(fn) {
|
||||
onShowEvents.value.push(fn)
|
||||
@ -53,8 +55,10 @@ export default function useGuard() {
|
||||
const route = routes.find(i => page && i.path === page.route);
|
||||
const requireLogin = route && route.meta && route.meta.login;
|
||||
if (requireLogin && !account.value) {
|
||||
const res = await login()
|
||||
if (res) {
|
||||
await login()
|
||||
console.log('login success')
|
||||
console.log(account.value)
|
||||
if (account.value) {
|
||||
resolve()
|
||||
} else {
|
||||
return toLoginPage(opts, page.route);
|
||||
|
||||
26
pages.json
@ -19,18 +19,18 @@
|
||||
"navigationBarTitleText": "常用语"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/case/case",
|
||||
"style": {
|
||||
"navigationBarTitleText": "病例"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/work",
|
||||
"style": {
|
||||
"navigationBarTitleText": "工作台"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/case/case",
|
||||
"style": {
|
||||
"navigationBarTitleText": "病例"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/profile",
|
||||
"style": {
|
||||
@ -43,10 +43,22 @@
|
||||
"navigationBarTitleText": "选择科室"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/verify/assistant",
|
||||
"style": {
|
||||
"navigationBarTitleText": "上传证照"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/verify/doctor",
|
||||
"style": {
|
||||
"navigationBarTitleText": "上传证照"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
"navigationBarTitleText": "授权登录"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view v-if="team" class="pt-lg px-15 flex flex-col items-center text-center">
|
||||
<!-- <view v-if="team" class="pt-lg px-15 flex flex-col items-center text-center">
|
||||
<group-avatar :avatarList="team.avatars" />
|
||||
<view class="mt-15 text-base font-semibold text-dark">{{
|
||||
team.teamName
|
||||
@ -8,20 +8,15 @@
|
||||
<view class="mt-15 text-lg text-dark font-semibold"
|
||||
>为您提供团队个性化专属服务</view
|
||||
>
|
||||
</view>
|
||||
<view v-else class="pt-lg px-15 flex flex-col items-center text-center">
|
||||
v-else
|
||||
</view> -->
|
||||
<view class="pt-lg px-15 flex flex-col items-center text-center">
|
||||
<image src="/static/logo-plain.png" class="logo"></image>
|
||||
<view class="mt-15 text-xl font-semibold text-dark">柚健康</view>
|
||||
<view class="mt-12 text-base text-dark">生命全周期健康管理伙伴</view>
|
||||
</view>
|
||||
<view class="login-btn-wrap">
|
||||
<button
|
||||
v-if="checked"
|
||||
class="login-btn"
|
||||
type="primary"
|
||||
open-type="getPhoneNumber"
|
||||
@getphonenumber="getPhoneNumber"
|
||||
>
|
||||
<button v-if="checked" class="login-btn" type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
|
||||
手机号快捷登录
|
||||
</button>
|
||||
<!-- <button v-if="checked" class="login-btn" type="primary" @click="getPhoneNumber()">
|
||||
@ -31,10 +26,7 @@
|
||||
手机号快捷登录
|
||||
</button>
|
||||
</view>
|
||||
<view
|
||||
class="flex items-center justify-center mt-12 px-15"
|
||||
@click="checked = !checked"
|
||||
>
|
||||
<view class="flex items-center justify-center mt-12 px-15" @click="checked = !checked">
|
||||
<checkbox :checked="checked" style="transform: scale(0.7)" />
|
||||
<view class="text-sm text-gray">我已阅读并同意</view>
|
||||
<view class="text-sm text-primary">《用户协议》、</view>
|
||||
@ -44,16 +36,16 @@
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import useAccountStore from "@/store/account";
|
||||
import { get } from "@/utils/cache";
|
||||
import { toast } from "@/utils/widget";
|
||||
|
||||
import groupAvatar from "@/components/group-avatar.vue";
|
||||
|
||||
const team = ref(true);
|
||||
const checked = ref(false);
|
||||
const redirectUrl = ref("");
|
||||
const { doctorInfo } = storeToRefs(useAccountStore());
|
||||
const { login } = useAccountStore();
|
||||
|
||||
function attempRedirect(url) {
|
||||
@ -81,8 +73,8 @@ function remind() {
|
||||
}
|
||||
|
||||
function toHome() {
|
||||
uni.navigateTo({
|
||||
url: "/pages/message/message",
|
||||
uni.switchTab({
|
||||
url: "/pages/work/work",
|
||||
});
|
||||
}
|
||||
|
||||
@ -92,6 +84,10 @@ async function getPhoneNumber(e) {
|
||||
const res = await login(phoneCode);
|
||||
if (res && redirectUrl.value) {
|
||||
await attempToPage(redirectUrl.value);
|
||||
} else if (res && !doctorInfo.value) {
|
||||
uni.redirectTo({
|
||||
url: '/pages/work/profile'
|
||||
})
|
||||
} else if (res) {
|
||||
toHome();
|
||||
}
|
||||
@ -109,7 +105,6 @@ onLoad((opts) => {
|
||||
if (opts.source === "teamInvite") {
|
||||
team.value = get("invite-team-info");
|
||||
redirectUrl.value = `/pages/archive/edit-archive?teamId=${team.value.teamId}&corpId=${team.value.corpId}`;
|
||||
console.log("redirectUrl", redirectUrl.value);
|
||||
return;
|
||||
}
|
||||
if (opts.redirect) {
|
||||
|
||||
@ -1,18 +1,5 @@
|
||||
<template>
|
||||
<view class="common-phrases-page">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<view class="navbar-content">
|
||||
|
||||
<view class="navbar-center">
|
||||
<text class="navbar-title">快捷回复</text>
|
||||
</view>
|
||||
<view class="navbar-right" @click="toggleEditMode">
|
||||
<text class="edit-text">{{ isEditMode ? '完成' : '编辑' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content-wrapper">
|
||||
<!-- 左侧分类列表 -->
|
||||
<view class="category-sidebar">
|
||||
@ -25,26 +12,36 @@
|
||||
@click="switchCategory(category.id)"
|
||||
@longpress="handleCategoryLongPress(category)"
|
||||
>
|
||||
<view class="category-name">{{ category.name }}</view>
|
||||
<view v-if="currentCategory === category.id" class="active-indicator"></view>
|
||||
<view v-if="isEditMode && category.deletable" class="delete-badge" @click.stop="deleteCategory(category)">
|
||||
<view class="category-content">
|
||||
<text class="category-name">{{ category.name }}</text>
|
||||
<view
|
||||
v-if="isEditMode && category.deletable"
|
||||
class="delete-badge"
|
||||
@click.stop="deleteCategory(category)"
|
||||
>
|
||||
<text class="delete-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="add-category-item" @click="showAddCategoryDialog">
|
||||
<text class="plus-icon">+</text>
|
||||
<text>加分类</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 右侧常用语列表 -->
|
||||
<view class="phrases-container">
|
||||
<view class="add-phrase-header" @click="showAddPhraseDialog">
|
||||
<!-- 顶部操作栏 -->
|
||||
<view class="action-bar">
|
||||
<view class="add-phrase-btn" @click="showAddPhraseDialog">
|
||||
<text class="add-icon">+</text>
|
||||
<text class="add-text">添加快捷回复</text>
|
||||
</view>
|
||||
<view class="edit-btn" @click="toggleEditMode">
|
||||
<text class="edit-text">{{ isEditMode ? "完成" : "编辑" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="phrases-list" scroll-y>
|
||||
<view
|
||||
@ -58,14 +55,16 @@
|
||||
<view class="action-btn edit" @click.stop="editPhrase(phrase)">
|
||||
<text>编辑</text>
|
||||
</view>
|
||||
<view class="action-btn delete" @click.stop="deletePhrase(phrase)">
|
||||
<view
|
||||
class="action-btn delete"
|
||||
@click.stop="deletePhrase(phrase)"
|
||||
>
|
||||
<text>删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="currentPhrases.length === 0" class="empty-state">
|
||||
<image src="/static/empty.svg" class="empty-icon" mode="aspectFit"></image>
|
||||
<text class="empty-text">暂无常用语</text>
|
||||
<text class="empty-hint">点击上方按钮添加常用语</text>
|
||||
</view>
|
||||
@ -77,7 +76,9 @@
|
||||
<view v-if="showPhrasePopup" class="popup-mask" @click="closePopup">
|
||||
<view class="popup-content" @click.stop>
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">{{ editingPhrase ? '编辑快捷回复' : '添加快捷回复' }}</text>
|
||||
<text class="popup-title">{{
|
||||
editingPhrase ? "编辑快捷回复" : "添加快捷回复"
|
||||
}}</text>
|
||||
<view class="popup-close" @click="closePopup">
|
||||
<text class="close-icon">×</text>
|
||||
</view>
|
||||
@ -92,13 +93,19 @@
|
||||
<view class="char-count">{{ phraseForm.content.length }}/500</view>
|
||||
<view class="popup-actions">
|
||||
<button class="cancel-btn" @click="closePopup">取消</button>
|
||||
<button class="confirm-btn" @click="savePhrase">{{ editingPhrase ? '保存' : '确认添加' }}</button>
|
||||
<button class="confirm-btn" @click="savePhrase">
|
||||
{{ editingPhrase ? "保存" : "确认添加" }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 添加分类弹窗 -->
|
||||
<view v-if="showCategoryPopup" class="popup-mask" @click="closeCategoryPopup">
|
||||
<view
|
||||
v-if="showCategoryPopup"
|
||||
class="popup-mask"
|
||||
@click="closeCategoryPopup"
|
||||
>
|
||||
<view class="popup-content category-popup" @click.stop>
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">新建分类</text>
|
||||
@ -122,8 +129,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import api from '@/utils/api';
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import api from "@/utils/api";
|
||||
|
||||
// 获取系统状态栏高度
|
||||
const statusBarHeight = ref(0);
|
||||
@ -133,19 +140,19 @@ const isEditMode = ref(false);
|
||||
|
||||
// 分类数据
|
||||
const categories = ref([
|
||||
{ id: 'visit', name: '文字随访', deletable: false },
|
||||
{ id: 'voice', name: '语音随访', deletable: false },
|
||||
{ id: 'common', name: '常用回复', deletable: false },
|
||||
{ id: "visit", name: "文字随访", deletable: false },
|
||||
{ id: "voice", name: "语音随访", deletable: false },
|
||||
{ id: "common", name: "常用回复", deletable: false },
|
||||
]);
|
||||
|
||||
const currentCategory = ref('common');
|
||||
const currentCategory = ref("common");
|
||||
|
||||
// 常用语数据
|
||||
const phrases = ref([]);
|
||||
|
||||
// 当前分类的常用语
|
||||
const currentPhrases = computed(() => {
|
||||
return phrases.value.filter(p => p.categoryId === currentCategory.value);
|
||||
return phrases.value.filter((p) => p.categoryId === currentCategory.value);
|
||||
});
|
||||
|
||||
// 弹窗显示状态
|
||||
@ -154,11 +161,11 @@ const showCategoryPopup = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const phraseForm = ref({
|
||||
content: ''
|
||||
content: "",
|
||||
});
|
||||
|
||||
const categoryForm = ref({
|
||||
name: ''
|
||||
name: "",
|
||||
});
|
||||
|
||||
const editingPhrase = ref(null);
|
||||
@ -198,7 +205,7 @@ const handlePhraseClick = (phrase) => {
|
||||
// 显示添加常用语弹窗
|
||||
const showAddPhraseDialog = () => {
|
||||
editingPhrase.value = null;
|
||||
phraseForm.value.content = '';
|
||||
phraseForm.value.content = "";
|
||||
showPhrasePopup.value = true;
|
||||
};
|
||||
|
||||
@ -213,8 +220,8 @@ const editPhrase = (phrase) => {
|
||||
const savePhrase = async () => {
|
||||
if (!phraseForm.value.content.trim()) {
|
||||
uni.showToast({
|
||||
title: '请输入内容',
|
||||
icon: 'none'
|
||||
title: "请输入内容",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -222,23 +229,25 @@ const savePhrase = async () => {
|
||||
try {
|
||||
if (editingPhrase.value) {
|
||||
// 更新
|
||||
await api('saveCommonPhrase', {
|
||||
await api("saveCommonPhrase", {
|
||||
id: editingPhrase.value.id,
|
||||
categoryId: editingPhrase.value.categoryId,
|
||||
content: phraseForm.value.content,
|
||||
corpId: uni.getStorageSync('corpId')
|
||||
corpId: uni.getStorageSync("corpId"),
|
||||
});
|
||||
|
||||
const index = phrases.value.findIndex(p => p.id === editingPhrase.value.id);
|
||||
const index = phrases.value.findIndex(
|
||||
(p) => p.id === editingPhrase.value.id
|
||||
);
|
||||
if (index !== -1) {
|
||||
phrases.value[index].content = phraseForm.value.content;
|
||||
}
|
||||
} else {
|
||||
// 新增
|
||||
const result = await api('saveCommonPhrase', {
|
||||
const result = await api("saveCommonPhrase", {
|
||||
categoryId: currentCategory.value,
|
||||
content: phraseForm.value.content,
|
||||
corpId: uni.getStorageSync('corpId')
|
||||
corpId: uni.getStorageSync("corpId"),
|
||||
});
|
||||
|
||||
if (result.code === 200 && result.data) {
|
||||
@ -248,22 +257,22 @@ const savePhrase = async () => {
|
||||
phrases.value.push({
|
||||
id: Date.now(),
|
||||
categoryId: currentCategory.value,
|
||||
content: phraseForm.value.content
|
||||
content: phraseForm.value.content,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: editingPhrase.value ? '保存成功' : '添加成功',
|
||||
icon: 'success'
|
||||
title: editingPhrase.value ? "保存成功" : "添加成功",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
closePopup();
|
||||
} catch (error) {
|
||||
console.error('保存常用语失败:', error);
|
||||
console.error("保存常用语失败:", error);
|
||||
uni.showToast({
|
||||
title: '操作失败',
|
||||
icon: 'none'
|
||||
title: "操作失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -271,40 +280,40 @@ const savePhrase = async () => {
|
||||
// 删除常用语
|
||||
const deletePhrase = (phrase) => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定删除该常用语吗?',
|
||||
title: "提示",
|
||||
content: "确定删除该常用语吗?",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await api('deleteCommonPhrase', {
|
||||
await api("deleteCommonPhrase", {
|
||||
id: phrase.id,
|
||||
corpId: uni.getStorageSync('corpId')
|
||||
corpId: uni.getStorageSync("corpId"),
|
||||
});
|
||||
|
||||
const index = phrases.value.findIndex(p => p.id === phrase.id);
|
||||
const index = phrases.value.findIndex((p) => p.id === phrase.id);
|
||||
if (index !== -1) {
|
||||
phrases.value.splice(index, 1);
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'success'
|
||||
title: "删除成功",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除常用语失败:', error);
|
||||
console.error("删除常用语失败:", error);
|
||||
uni.showToast({
|
||||
title: '删除失败',
|
||||
icon: 'none'
|
||||
title: "删除失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 显示添加分类弹窗
|
||||
const showAddCategoryDialog = () => {
|
||||
categoryForm.value.name = '';
|
||||
categoryForm.value.name = "";
|
||||
showCategoryPopup.value = true;
|
||||
};
|
||||
|
||||
@ -312,25 +321,71 @@ const showAddCategoryDialog = () => {
|
||||
const saveCategory = () => {
|
||||
if (!categoryForm.value.name.trim()) {
|
||||
uni.showToast({
|
||||
title: '请输入分类名',
|
||||
icon: 'none'
|
||||
title: "请输入分类名",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
categories.value.push({
|
||||
id: `category_${Date.now()}`,
|
||||
name: categoryForm.value.name
|
||||
name: categoryForm.value.name,
|
||||
deletable: true, // 用户添加的分类可删除
|
||||
});
|
||||
|
||||
uni.showToast({
|
||||
title: '添加成功',
|
||||
icon: 'success'
|
||||
title: "添加成功",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
closeCategoryPopup();
|
||||
};
|
||||
|
||||
// 长按分类
|
||||
const handleCategoryLongPress = (category) => {
|
||||
if (!category.deletable) return;
|
||||
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: `确定删除分类"${category.name}"吗?该分类下的所有常用语也将被删除。`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
deleteCategory(category);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 删除分类
|
||||
const deleteCategory = (category) => {
|
||||
if (!category.deletable) {
|
||||
uni.showToast({
|
||||
title: "默认分类不可删除",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 删除分类下的所有常用语
|
||||
phrases.value = phrases.value.filter((p) => p.categoryId !== category.id);
|
||||
|
||||
// 删除分类
|
||||
const index = categories.value.findIndex((c) => c.id === category.id);
|
||||
if (index !== -1) {
|
||||
categories.value.splice(index, 1);
|
||||
}
|
||||
|
||||
// 如果删除的是当前分类,切换到第一个分类
|
||||
if (currentCategory.value === category.id && categories.value.length > 0) {
|
||||
currentCategory.value = categories.value[0].id;
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: "删除成功",
|
||||
icon: "success",
|
||||
});
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const closePopup = () => {
|
||||
showPhrasePopup.value = false;
|
||||
@ -343,8 +398,8 @@ const closeCategoryPopup = () => {
|
||||
// 加载常用语数据
|
||||
const loadPhrases = async () => {
|
||||
try {
|
||||
const result = await api('getCommonPhrases', {
|
||||
corpId: uni.getStorageSync('corpId')
|
||||
const result = await api("getCommonPhrases", {
|
||||
corpId: uni.getStorageSync("corpId"),
|
||||
});
|
||||
|
||||
if (result.code === 200 && result.data) {
|
||||
@ -354,7 +409,7 @@ const loadPhrases = async () => {
|
||||
phrases.value = getMockPhrases();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载常用语失败:', error);
|
||||
console.error("加载常用语失败:", error);
|
||||
// 加载失败时使用模拟数据
|
||||
phrases.value = getMockPhrases();
|
||||
}
|
||||
@ -365,55 +420,62 @@ const getMockPhrases = () => {
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
categoryId: 'common',
|
||||
content: '想要买草药自己熬还是配方颗粒直接开水冲着喝?线上购买全国包邮,一二线城市一般1-2天送到,其他城市可能慢一些。'
|
||||
categoryId: "common",
|
||||
content:
|
||||
"想要买草药自己熬还是配方颗粒直接开水冲着喝?线上购买全国包邮,一二线城市一般1-2天送到,其他城市可能慢一些。",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
categoryId: 'common',
|
||||
content: '以前得过什么病吗?做过什么检查吗?有检查结果吗?详细说一下。'
|
||||
categoryId: "common",
|
||||
content: "以前得过什么病吗?做过什么检查吗?有检查结果吗?详细说一下。",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
categoryId: 'common',
|
||||
content: '把我之前给您开的处方,拍个照上传给我看一下,拍招清楚一点。'
|
||||
categoryId: "common",
|
||||
content: "把我之前给您开的处方,拍个照上传给我看一下,拍招清楚一点。",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
categoryId: 'common',
|
||||
content: '服药期间要慎炸身体,少吃油炸等辛辣食物,按时作息,精神放松。'
|
||||
categoryId: "common",
|
||||
content: "服药期间要慎炸身体,少吃油炸等辛辣食物,按时作息,精神放松。",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
categoryId: 'common',
|
||||
content: '煎药最好用砂锅,避免用铁锅,煎药前用冷水浸泡30分钟,水量超过药材2-5厘米,一般中药煎2次,第1次煮沸后再煎20分钟就可以倒出来了,再次加水煮沸后再煎30分钟后倒出,将2次倒出的药混合在一起,就可以按照医嘱用药了。'
|
||||
categoryId: "common",
|
||||
content:
|
||||
"煎药最好用砂锅,避免用铁锅,煎药前用冷水浸泡30分钟,水量超过药材2-5厘米,一般中药煎2次,第1次煮沸后再煎20分钟就可以倒出来了,再次加水煮沸后再煎30分钟后倒出,将2次倒出的药混合在一起,就可以按照医嘱用药了。",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
categoryId: 'common',
|
||||
content: '如果在线上买药,点击整体治疗方案,选择首选处方,划价取药,填写地址后去付款即可。'
|
||||
categoryId: "common",
|
||||
content:
|
||||
"如果在线上买药,点击整体治疗方案,选择首选处方,划价取药,填写地址后去付款即可。",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
categoryId: 'voice',
|
||||
content: '想要买草药自己熬还是配方颗粒直接开水冲着喝?'
|
||||
categoryId: "voice",
|
||||
content: "想要买草药自己熬还是配方颗粒直接开水冲着喝?",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
categoryId: 'visit',
|
||||
content: '您好,我是您的健康管理师,请问有什么可以帮助您的吗?'
|
||||
}
|
||||
categoryId: "visit",
|
||||
content: "您好,我是您的健康管理师,请问有什么可以帮助您的吗?",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 获取系统信息
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
statusBarHeight.value = systemInfo.statusBarHeight || 0;
|
||||
|
||||
loadPhrases();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// 使用项目主题色
|
||||
$primary-color: #0877F1;
|
||||
$primary-color: #0877f1;
|
||||
$primary-light: #e8f3ff;
|
||||
$primary-gradient-start: #1b5cc8;
|
||||
$primary-gradient-end: #0877f1;
|
||||
@ -425,108 +487,112 @@ $primary-gradient-end: #0877f1;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 32rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #eee;
|
||||
// 自定义导航栏
|
||||
.custom-navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
$primary-gradient-end 0%,
|
||||
$primary-gradient-start 100%
|
||||
);
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2rpx 12rpx rgba(8, 119, 241, 0.15);
|
||||
}
|
||||
|
||||
.title {
|
||||
.navbar-content {
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 32rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navbar-left {
|
||||
width: 80rpx;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
.back-icon {
|
||||
font-size: 56rpx;
|
||||
color: #fff;
|
||||
font-weight: 300;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-center {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.navbar-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
font-size: 28rpx;
|
||||
color: $primary-color;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
.navbar-right {
|
||||
width: 80rpx;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// 左侧分类栏
|
||||
.category-sidebar {
|
||||
width: 200rpx;
|
||||
background-color: #f8f8f8;
|
||||
border-right: 1px solid #e5e5e5;
|
||||
|
||||
.category-list {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
position: relative;
|
||||
padding: 32rpx 24rpx;
|
||||
text-align: center;
|
||||
background-color: #f8f8f8;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
|
||||
.category-name {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #fff;
|
||||
|
||||
.category-name {
|
||||
color: $primary-color;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.active-indicator {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 6rpx;
|
||||
height: 40rpx;
|
||||
background-color: $primary-color;
|
||||
border-radius: 0 4rpx 4rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-category-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 32rpx 24rpx;
|
||||
justify-content: flex-end;
|
||||
|
||||
.more-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
padding: 12rpx 16rpx;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 40rpx;
|
||||
|
||||
.dot {
|
||||
font-size: 24rpx;
|
||||
color: $primary-color;
|
||||
background-color: #f8f8f8;
|
||||
|
||||
.plus-icon {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8rpx;
|
||||
color: #fff;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 右侧内容区
|
||||
.phrases-container {
|
||||
flex: 1;
|
||||
// 标题栏
|
||||
.action-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
margin: 24rpx 24rpx 0;
|
||||
.edit-btn {
|
||||
padding: 16rpx 32rpx;
|
||||
.edit-text {
|
||||
font-size: 28rpx;
|
||||
color: $primary-color;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.add-phrase-header {
|
||||
.add-phrase-btn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24rpx;
|
||||
background: linear-gradient(270deg, $primary-gradient-start 2.26%, $primary-gradient-end 94.33%);
|
||||
border-bottom: 1px solid rgba(8, 119, 241, 0.1);
|
||||
padding: 16rpx 24rpx;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
$primary-gradient-end 0%,
|
||||
$primary-gradient-start 100%
|
||||
);
|
||||
border-radius: 40rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(8, 119, 241, 0.2);
|
||||
|
||||
.add-icon {
|
||||
font-size: 32rpx;
|
||||
@ -541,22 +607,130 @@ $primary-gradient-end: #0877f1;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// 左侧分类栏
|
||||
.category-sidebar {
|
||||
width: 180rpx;
|
||||
background-color: #fff;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
|
||||
.category-list {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
position: relative;
|
||||
padding: 40rpx 16rpx;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
transition: all 0.3s;
|
||||
|
||||
.category-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $primary-light;
|
||||
|
||||
.category-name {
|
||||
color: $primary-color;
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.delete-badge {
|
||||
position: absolute;
|
||||
top: -12rpx;
|
||||
right: 8rpx;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
background-color: #ff3b30;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(255, 59, 48, 0.3);
|
||||
|
||||
.delete-icon {
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
line-height: 1;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-category-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx 16rpx;
|
||||
font-size: 24rpx;
|
||||
color: $primary-color;
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
|
||||
.plus-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 40rpx;
|
||||
font-weight: 300;
|
||||
color: $primary-color;
|
||||
background-color: $primary-light;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 右侧内容区
|
||||
.phrases-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.phrases-list {
|
||||
flex: 1;
|
||||
padding: 24rpx;
|
||||
height: 0; // 配合 flex: 1 实现固定高度
|
||||
overflow-y: auto; // 支持垂直滚动
|
||||
|
||||
.phrase-item {
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 12rpx;
|
||||
border-left: 4rpx solid $primary-color;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
border-left: 6rpx solid $primary-color;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.phrase-content {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.phrase-actions {
|
||||
@ -564,13 +738,14 @@ $primary-gradient-end: #0877f1;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16rpx;
|
||||
padding-top: 16rpx;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
gap: 16rpx;
|
||||
|
||||
.action-btn {
|
||||
padding: 8rpx 24rpx;
|
||||
margin-left: 16rpx;
|
||||
padding: 10rpx 28rpx;
|
||||
font-size: 24rpx;
|
||||
border-radius: 8rpx;
|
||||
border-radius: 40rpx;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.edit {
|
||||
color: $primary-color;
|
||||
@ -590,17 +765,17 @@ $primary-gradient-end: #0877f1;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
padding: 160rpx 0;
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
font-size: 32rpx;
|
||||
color: #999;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -611,69 +786,114 @@ $primary-gradient-end: #0877f1;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
z-index: 9999;
|
||||
backdrop-filter: blur(4rpx);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
width: 600rpx;
|
||||
padding: 32rpx;
|
||||
padding: 40rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
border-radius: 24rpx;
|
||||
max-height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 32rpx;
|
||||
|
||||
.popup-title {
|
||||
font-size: 32rpx;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.popup-close {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 50%;
|
||||
|
||||
.close-icon {
|
||||
font-size: 40rpx;
|
||||
color: #999;
|
||||
line-height: 1;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.phrase-textarea {
|
||||
width: 100%;
|
||||
min-height: 300rpx;
|
||||
padding: 16rpx;
|
||||
max-height: 500rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 24rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid #e9ecef;
|
||||
margin-bottom: 12rpx;
|
||||
box-sizing: border-box;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.category-input {
|
||||
width: 100%;
|
||||
padding: 16rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 24rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid #e9ecef;
|
||||
margin-bottom: 32rpx;
|
||||
box-sizing: border-box;
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.popup-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
padding: 10rpx;
|
||||
font-size: 28rpx;
|
||||
border-radius: 8rpx;
|
||||
border-radius: 12rpx;
|
||||
border: none;
|
||||
|
||||
font-weight: 500;
|
||||
&.cancel-btn {
|
||||
margin-right: 16rpx;
|
||||
color: #666;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
&.confirm-btn {
|
||||
color: #fff;
|
||||
background: linear-gradient(270deg, $primary-gradient-start 2.26%, $primary-gradient-end 94.33%);
|
||||
box-shadow: 0 2rpx 8rpx rgba(8, 119, 241, 0.2);
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
$primary-gradient-end 0%,
|
||||
$primary-gradient-start 100%
|
||||
);
|
||||
box-shadow: 0 4rpx 12rpx rgba(8, 119, 241, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
64
pages/work/components/cert-popup.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<uni-popup ref="popup" type="center" :mask-click="false">
|
||||
<view class="bg-white rounded overflow-hidden" style="width: 690rpx;">
|
||||
<view class="px-15 py-12 text-center text-lg font-semibold text-dark">
|
||||
认证须知
|
||||
</view>
|
||||
<view class="text-base text-dark px-15 leading-normal font-semibold mt-10">
|
||||
1、认证通过后,您个人账号病历档案管理数(含所有团队)上限由10个升级至100个;
|
||||
</view>
|
||||
<view class="px-15 leading-normal mt-10 ">
|
||||
<text class="text-base text-dark">2、认证前请仔细核对个人信息,确保准确无误。认证后部分信息不支持修改,包括姓名、岗位等。如需修改以上信息,请联系客服人工处理</text>
|
||||
</view>
|
||||
<view class="mt-10 px-15 leading-normal font-semibold pb-50 text-lg text-primary" @click="toService()">点击添加客服
|
||||
</view>
|
||||
<view class="footer-buttons">
|
||||
<button-footer hideden-shadow confirmText="去认证" @confirm="confirm()" @cancel="close()" />
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import ButtonFooter from '@/components/button-footer.vue';
|
||||
|
||||
const emits = defineEmits(['close', 'confirm'])
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
const popup = ref()
|
||||
|
||||
function close() {
|
||||
emits('close')
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
close()
|
||||
uni.navigateTo({
|
||||
url: "/pages/work/profile?type=cert",
|
||||
});
|
||||
}
|
||||
|
||||
function toService() {
|
||||
close()
|
||||
}
|
||||
|
||||
watch(() => props.visible, n => {
|
||||
if (n) {
|
||||
popup.value && popup.value.open()
|
||||
} else {
|
||||
popup.value && popup.value.close()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pb-50 {
|
||||
padding-bottom: 100rpx;
|
||||
}
|
||||
</style>
|
||||
308
pages/work/profile copy.vue
Normal file
@ -0,0 +1,308 @@
|
||||
<template>
|
||||
<view class="profile-page">
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-section bg-white">
|
||||
<!-- 姓名 -->
|
||||
<form-input
|
||||
name="姓名"
|
||||
:required="true"
|
||||
:form="formData"
|
||||
title="anotherName"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<!-- 头像 -->
|
||||
<common-cell name="头像">
|
||||
<view class="form-content__wrapper" @click="chooseAvatar">
|
||||
<view class="flex-main-content flex items-center">
|
||||
<image
|
||||
v-if="formData.avatar"
|
||||
class="avatar-preview"
|
||||
:src="formData.avatar"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
<uni-icons class="form-arrow" type="arrowright"></uni-icons>
|
||||
</view>
|
||||
</common-cell>
|
||||
<!-- 性别 -->
|
||||
<form-select
|
||||
name="性别"
|
||||
:form="formData"
|
||||
title="gender"
|
||||
:range="genderOptions"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<!-- 手机号(不可修改) -->
|
||||
<common-cell name="手机号 (不可修改)">
|
||||
<view class="form-content__wrapper">
|
||||
<view class="flex-main-content text-dark">{{ formData.mobile }}</view>
|
||||
</view>
|
||||
</common-cell>
|
||||
<!-- 岗位 -->
|
||||
<form-select
|
||||
name="岗位"
|
||||
:form="formData"
|
||||
title="position"
|
||||
:range="positionOptions"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<!-- 职称 -->
|
||||
<form-select
|
||||
name="职称"
|
||||
:form="formData"
|
||||
title="title"
|
||||
:range="titleOptions"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<!-- 科室 -->
|
||||
<common-cell name="科室">
|
||||
<view class="form-content__wrapper" @click="openDepartmentSelect">
|
||||
<view
|
||||
class="flex-main-content text-right"
|
||||
:class="{ 'text-placeholder': !formData.departmentName }"
|
||||
>
|
||||
{{ formData.departmentName || "请选择" }}
|
||||
</view>
|
||||
<uni-icons class="form-arrow" type="arrowright"></uni-icons>
|
||||
</view>
|
||||
</common-cell>
|
||||
|
||||
<!-- 个人介绍 -->
|
||||
<form-textarea
|
||||
name="个人介绍"
|
||||
:form="formData"
|
||||
title="intro"
|
||||
:word-limit="500"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
</view>
|
||||
<!-- 底部按钮 -->
|
||||
<view class="button-footer">
|
||||
<view class="btn btn-cancel" @click="handleCancel">取消</view>
|
||||
<view class="btn btn-save" @click="handleSave">保存</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
import useGuard from "@/hooks/useGuard.js";
|
||||
import { chooseAndUploadImage } from "@/utils/file.js";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import { storeToRefs } from "pinia";
|
||||
import CommonCell from "@/components/form-template/common-cell.vue";
|
||||
import FormInput from "@/components/form-template/form-cell/form-input.vue";
|
||||
import FormSelect from "@/components/form-template/form-cell/form-select.vue";
|
||||
import FormTextarea from "@/components/form-template/form-cell/form-textarea.vue";
|
||||
import api from "@/utils/api.js";
|
||||
const { account, doctorInfo } = storeToRefs(useAccountStore());
|
||||
const { useLoad } = useGuard();
|
||||
const { getDoctorInfo } = useAccountStore();
|
||||
// 表单数据
|
||||
const formData = ref({
|
||||
anotherName: "",
|
||||
avatar: "",
|
||||
gender: "",
|
||||
mobile: "",
|
||||
position: "",
|
||||
title: "",
|
||||
department: "",
|
||||
departmentName: "",
|
||||
departmentId: "",
|
||||
intro: "",
|
||||
});
|
||||
|
||||
// 选项数据
|
||||
const genderOptions = [
|
||||
{ label: "男", value: "0" },
|
||||
{ label: "女", value: "1" },
|
||||
];
|
||||
const positionOptions = ["医生", "护士", "药师", "技师", "其他"];
|
||||
const titleOptions = ["主任医师", "副主任医师", "主治医师", "医师", "其他"];
|
||||
// 字段变更处理
|
||||
const handleFieldChange = (e) => {
|
||||
if (e.title === "gender") {
|
||||
formData.value[e.title] = e.value.value;
|
||||
} else {
|
||||
formData.value[e.title] = e.value;
|
||||
}
|
||||
};
|
||||
|
||||
// 选择头像
|
||||
const chooseAvatar = async () => {
|
||||
const url = await chooseAndUploadImage();
|
||||
if (url) {
|
||||
formData.value.avatar = url;
|
||||
}
|
||||
};
|
||||
const handleCancel = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
createDoctorInfo();
|
||||
};
|
||||
useLoad(() => {
|
||||
if (doctorInfo.value) {
|
||||
formData.value = { ...doctorInfo.value };
|
||||
} else {
|
||||
formData.value.mobile = account.value.mobile;
|
||||
}
|
||||
});
|
||||
|
||||
// 创建医生信息
|
||||
const createDoctorInfo = async () => {
|
||||
if (!formData.value.anotherName) {
|
||||
uni.showToast({
|
||||
title: "请输入姓名",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
let params = {
|
||||
anotherName: formData.value.anotherName,
|
||||
avatar: formData.value.avatar,
|
||||
gender: formData.value.gender,
|
||||
mobile: formData.value.mobile,
|
||||
weChatOpenId: account.value.openid,
|
||||
deptIds: [],
|
||||
loginTypes: ["wxApp"],
|
||||
corpId: account.value.corpId,
|
||||
};
|
||||
const res = await api("addCorpMember", {
|
||||
params,
|
||||
});
|
||||
if (res.success && res.data) {
|
||||
uni.showToast({
|
||||
title: "创建成功",
|
||||
icon: "success",
|
||||
});
|
||||
await getDoctorInfo();
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: "创建失败",
|
||||
icon: "none",
|
||||
});
|
||||
console.error("创建医生信息失败:", res);
|
||||
}
|
||||
};
|
||||
|
||||
const updateDoctorInfo = async () => {
|
||||
let params = {
|
||||
anotherName: formData.value.anotherName,
|
||||
avatar: formData.value.avatar,
|
||||
gender: formData.value.gender,
|
||||
};
|
||||
const res = await api("updateCorpMember", {
|
||||
params,
|
||||
});
|
||||
if (res.success && res.data) {
|
||||
uni.showToast({
|
||||
title: "更新成功",
|
||||
icon: "success",
|
||||
});
|
||||
}
|
||||
await getDoctorInfo();
|
||||
uni.navigateBack();
|
||||
};
|
||||
// 打开科室选择
|
||||
const openDepartmentSelect = () => {
|
||||
uni.navigateTo({
|
||||
url: "/pages/work/department-select",
|
||||
events: {
|
||||
deptSelected: ({ name, deptId }) => {
|
||||
formData.value.department = name || "";
|
||||
formData.value.departmentName = name || "";
|
||||
formData.value.departmentId = deptId || "";
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.profile-page {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.form-content__wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
font-size: 28rpx;
|
||||
|
||||
input {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.text-placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.avatar-preview {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
background: #e5e5e5;
|
||||
}
|
||||
|
||||
.avatar-placeholder {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
background: #e5e5e5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.avatar-icon {
|
||||
font-size: 48rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.button-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
padding: 20rpx 30rpx;
|
||||
background: #fff;
|
||||
border-top: 1px solid #eee;
|
||||
gap: 20rpx;
|
||||
z-index: 100;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
text-align: center;
|
||||
border-radius: 8rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
background: #fff;
|
||||
border: 1px solid #007aff;
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,211 +1,83 @@
|
||||
<template>
|
||||
<view class="profile-page">
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-section bg-white">
|
||||
<!-- 姓名 -->
|
||||
<form-input
|
||||
name="姓名"
|
||||
:required="true"
|
||||
:form="formData"
|
||||
title="anotherName"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<!-- 头像 -->
|
||||
<common-cell name="头像">
|
||||
<view class="form-content__wrapper" @click="chooseAvatar">
|
||||
<view class="flex-main-content flex items-center">
|
||||
<image
|
||||
v-if="formData.avatar"
|
||||
class="avatar-preview"
|
||||
:src="formData.avatar"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
<uni-icons class="form-arrow" type="arrowright"></uni-icons>
|
||||
<full-page>
|
||||
<view class="p-15">
|
||||
<view class="bg-white px-10 mb-10 rounded">
|
||||
<form-input :form="formData" required wordLimit="10" title="anotherName" name="姓名" @change="onChange($event)" />
|
||||
<common-cell title="avatar" name="头像">
|
||||
<view class="flex-grow flex items-center justify-end" @click="chooseAvatar()">
|
||||
<image v-if="formData.avatar" class="avatar mr-5 rounded-full" :src="formData.avatar" />
|
||||
<image v-else class="avatar mr-5 rounded-full" src="/static/default-avatar.png" />
|
||||
<uni-icons color="#999" type="right" size="16" />
|
||||
</view>
|
||||
</common-cell>
|
||||
<!-- 性别 -->
|
||||
<form-select
|
||||
name="性别"
|
||||
:form="formData"
|
||||
title="gender"
|
||||
:range="genderOptions"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<!-- 手机号(不可修改) -->
|
||||
<common-cell name="手机号 (不可修改)">
|
||||
<view class="form-content__wrapper">
|
||||
<view class="flex-main-content text-dark">{{ formData.mobile }}</view>
|
||||
<form-select :form="formData" name="性别" title="gender" :range="genderOptions" @change="onChange($event)" />
|
||||
<form-input :form="formData" disableChange wordLimit="11" title="mobile" name="手机号 (不可修改)" />
|
||||
</view>
|
||||
</common-cell>
|
||||
<!-- 岗位 -->
|
||||
<form-select
|
||||
name="岗位"
|
||||
:form="formData"
|
||||
title="position"
|
||||
:range="positionOptions"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<!-- 职称 -->
|
||||
<form-select
|
||||
name="职称"
|
||||
:form="formData"
|
||||
title="title"
|
||||
:range="titleOptions"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<!-- 科室 -->
|
||||
<common-cell name="科室">
|
||||
<view class="form-content__wrapper" @click="openDepartmentSelect">
|
||||
<view
|
||||
class="flex-main-content text-right"
|
||||
:class="{ 'text-placeholder': !formData.departmentName }"
|
||||
>
|
||||
{{ formData.departmentName || "请选择" }}
|
||||
</view>
|
||||
<uni-icons class="form-arrow" type="arrowright"></uni-icons>
|
||||
</view>
|
||||
</common-cell>
|
||||
|
||||
<!-- 个人介绍 -->
|
||||
<form-textarea
|
||||
name="个人介绍"
|
||||
:form="formData"
|
||||
title="intro"
|
||||
:word-limit="500"
|
||||
@change="handleFieldChange"
|
||||
/>
|
||||
<view class="bg-white px-10 mb-10 rounded">
|
||||
<common-cell title="avatar" name="岗位">
|
||||
<view class="flex-grow flex items-center justify-end">
|
||||
<!-- <view class="mr-5 rounded-full" style="width: 64rpx;height: 64rpx;background: red;"></view> -->
|
||||
<uni-icons color="#999" type="right" size="16" />
|
||||
</view>
|
||||
<!-- 底部按钮 -->
|
||||
<view class="button-footer">
|
||||
<view class="btn btn-cancel" @click="handleCancel">取消</view>
|
||||
<view class="btn btn-save" @click="handleSave">保存</view>
|
||||
</common-cell>
|
||||
<common-cell title="avatar" name="职称">
|
||||
<view class="flex-grow flex items-center justify-end">
|
||||
<!-- <view class="mr-5 rounded-full" style="width: 64rpx;height: 64rpx;background: red;"></view> -->
|
||||
<uni-icons color="#999" type="right" size="16" />
|
||||
</view>
|
||||
</common-cell>
|
||||
<common-cell title="avatar" name="科室">
|
||||
<view class="flex-grow flex items-center justify-end">
|
||||
<!-- <view class="mr-5 rounded-full" style="width: 64rpx;height: 64rpx;background: red;"></view> -->
|
||||
<uni-icons color="#999" type="right" size="16" />
|
||||
</view>
|
||||
</common-cell>
|
||||
</view>
|
||||
|
||||
<view class="bg-white rounded">
|
||||
<form-textarea :border="false" :form="formData" title="intro" name="个人介绍" :wordLimit="300"
|
||||
@change="onChange($event)" />
|
||||
</view>
|
||||
</view>
|
||||
<template #footer>
|
||||
<button-footer :cancelText="cancelText" :confirmText="confirmText" @confirm="save()" @cancel="back()" />
|
||||
</template>
|
||||
</full-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import useGuard from "@/hooks/useGuard.js";
|
||||
import { chooseAndUploadImage } from "@/utils/file.js";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import { computed, ref } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import CommonCell from "@/components/form-template/common-cell.vue";
|
||||
import useGuard from "@/hooks/useGuard.js";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import api from "@/utils/api.js";
|
||||
import { upload } from "@/utils/http.js";
|
||||
import { toast } from "@/utils/widget";
|
||||
|
||||
import buttonFooter from '@/components/button-footer.vue';
|
||||
import commonCell from "@/components/form-template/common-cell.vue";
|
||||
import FormInput from "@/components/form-template/form-cell/form-input.vue";
|
||||
import FormSelect from "@/components/form-template/form-cell/form-select.vue";
|
||||
import FormTextarea from "@/components/form-template/form-cell/form-textarea.vue";
|
||||
import api from "@/utils/api.js";
|
||||
import fullPage from '@/components/full-page.vue';
|
||||
|
||||
const { account, doctorInfo } = storeToRefs(useAccountStore());
|
||||
const { useLoad } = useGuard();
|
||||
const { useLoad, useShow } = useGuard();
|
||||
const { getDoctorInfo } = useAccountStore();
|
||||
// 表单数据
|
||||
const formData = ref({
|
||||
anotherName: "",
|
||||
avatar: "",
|
||||
gender: "",
|
||||
mobile: "",
|
||||
position: "",
|
||||
title: "",
|
||||
department: "",
|
||||
departmentName: "",
|
||||
departmentId: "",
|
||||
intro: "",
|
||||
});
|
||||
|
||||
const form = ref({});
|
||||
const type = ref('')
|
||||
const formData = computed(() => ({ ...(doctorInfo.value || {}), ...form.value, mobile: account.value?.mobile }));
|
||||
const cancelText = computed(() => doctorInfo.value ? '取消' : '暂不填写');
|
||||
const confirmText = computed(() => type.value === 'cert' ? '下一步' : '保存');
|
||||
|
||||
// 选项数据
|
||||
const genderOptions = [
|
||||
{ label: "男", value: "0" },
|
||||
{ label: "女", value: "1" },
|
||||
];
|
||||
const positionOptions = ["医生", "护士", "药师", "技师", "其他"];
|
||||
const titleOptions = ["主任医师", "副主任医师", "主治医师", "医师", "其他"];
|
||||
// 字段变更处理
|
||||
const handleFieldChange = (e) => {
|
||||
if (e.title === "gender") {
|
||||
formData.value[e.title] = e.value.value;
|
||||
} else {
|
||||
formData.value[e.title] = e.value;
|
||||
}
|
||||
};
|
||||
|
||||
// 选择头像
|
||||
const chooseAvatar = async () => {
|
||||
const url = await chooseAndUploadImage();
|
||||
if (url) {
|
||||
formData.value.avatar = url;
|
||||
}
|
||||
};
|
||||
const handleCancel = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
createDoctorInfo();
|
||||
};
|
||||
useLoad(() => {
|
||||
if (doctorInfo.value) {
|
||||
formData.value = { ...doctorInfo.value };
|
||||
} else {
|
||||
formData.value.mobile = account.value.mobile;
|
||||
}
|
||||
});
|
||||
|
||||
// 创建医生信息
|
||||
const createDoctorInfo = async () => {
|
||||
if (!formData.value.anotherName) {
|
||||
uni.showToast({
|
||||
title: "请输入姓名",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
let params = {
|
||||
anotherName: formData.value.anotherName,
|
||||
avatar: formData.value.avatar,
|
||||
gender: formData.value.gender,
|
||||
mobile: formData.value.mobile,
|
||||
weChatOpenId: account.value.openid,
|
||||
deptIds: [],
|
||||
loginTypes: ["wxApp"],
|
||||
corpId: account.value.corpId,
|
||||
};
|
||||
const res = await api("addCorpMember", {
|
||||
params,
|
||||
});
|
||||
if (res.success && res.data) {
|
||||
uni.showToast({
|
||||
title: "创建成功",
|
||||
icon: "success",
|
||||
});
|
||||
await getDoctorInfo();
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: "创建失败",
|
||||
icon: "none",
|
||||
});
|
||||
console.error("创建医生信息失败:", res);
|
||||
}
|
||||
};
|
||||
|
||||
const updateDoctorInfo = async () => {
|
||||
let params = {
|
||||
anotherName: formData.value.anotherName,
|
||||
avatar: formData.value.avatar,
|
||||
gender: formData.value.gender,
|
||||
};
|
||||
const res = await api("updateCorpMember", {
|
||||
params,
|
||||
});
|
||||
if (res.success && res.data) {
|
||||
uni.showToast({
|
||||
title: "更新成功",
|
||||
icon: "success",
|
||||
});
|
||||
}
|
||||
await getDoctorInfo();
|
||||
uni.navigateBack();
|
||||
};
|
||||
// 打开科室选择
|
||||
const openDepartmentSelect = () => {
|
||||
uni.navigateTo({
|
||||
@ -219,89 +91,74 @@ const openDepartmentSelect = () => {
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
function back() {
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
uni.switchTab({
|
||||
url: "/pages/work/work",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function chooseAvatar() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: async (res) => {
|
||||
const [path] = res.tempFilePaths;
|
||||
const url = await upload(path);
|
||||
if (url) {
|
||||
form.value.avatar = url;
|
||||
} else {
|
||||
toast('上传失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onChange({ title, value }) {
|
||||
form.value[title] = value
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (typeof formData.value.anotherName !== 'string' || !formData.value.anotherName.trim()) {
|
||||
return toast('请输入姓名')
|
||||
}
|
||||
if (type.value === 'cert' && !formData.value.departmentId) {
|
||||
return toast('请输入岗位信息')
|
||||
}
|
||||
const apiName = doctorInfo.value ? 'updateCorpMemberFromWxapp' : 'addCorpMemberFromWxapp';
|
||||
const data = {
|
||||
...form.value,
|
||||
weChatOpenId: account.value.openid,
|
||||
mobile: account.value.mobile,
|
||||
corpId: account.value.corpId,
|
||||
}
|
||||
const res = await api(apiName, data);
|
||||
if (res && res.success) {
|
||||
await toast('保存成功');
|
||||
await getDoctorInfo()
|
||||
back()
|
||||
} else {
|
||||
await toast(res?.message || '保存失败');
|
||||
}
|
||||
}
|
||||
|
||||
useLoad(opts => {
|
||||
type.value = opts?.type;
|
||||
})
|
||||
|
||||
useShow(() => {
|
||||
getDoctorInfo()
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.profile-page {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.form-content__wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
font-size: 28rpx;
|
||||
|
||||
input {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.text-placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.avatar-preview {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
background: #e5e5e5;
|
||||
}
|
||||
|
||||
.avatar-placeholder {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
background: #e5e5e5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.avatar-icon {
|
||||
font-size: 48rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.button-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
padding: 20rpx 30rpx;
|
||||
background: #fff;
|
||||
border-top: 1px solid #eee;
|
||||
gap: 20rpx;
|
||||
z-index: 100;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
text-align: center;
|
||||
border-radius: 8rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
background: #fff;
|
||||
border: 1px solid #007aff;
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
}
|
||||
.avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
164
pages/work/verify/assistant.vue
Normal file
@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<full-page pageClass="bg-white">
|
||||
<view class="p-15">
|
||||
<view class="mt-15 title-bar relative font-semibold">
|
||||
<text class="mr-5 text-dark text-base">请上传</text>
|
||||
<text class="text-primary text-base">身份证正反面</text>
|
||||
</view>
|
||||
<view class="mt-12 flex items-center justify-between">
|
||||
<view class="album border rounded overflow-hidden" @click="uploadIdCard('idCardFront')">
|
||||
<image v-if="form.idCardFront" class="w-full h-full" :src="form.idCardFront" />
|
||||
<view v-else class="relative w-full h-full ">
|
||||
<image class="absolute w-full h-full" src="/static/work/fIDCard.png" />
|
||||
<view class="absolute w-full h-full flex flex-col items-center justify-center">
|
||||
<image class="carmra-icon" src="/static/work/camera.png" />
|
||||
<view class="text-lg font-semibold color-428">上传人像面</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="album border rounded overflow-hidden" @click="uploadIdCard('idCardBack')">
|
||||
<image v-if="form.idCardBack" class="w-full h-full" :src="form.idCardBack" />
|
||||
<view v-else class="relative w-full h-full ">
|
||||
<image class="absolute w-full h-full" src="/static/work/aIDCard.png" />
|
||||
<view class="absolute w-full h-full flex flex-col items-center justify-center">
|
||||
<image class="carmra-icon" src="/static/work/camera.png" />
|
||||
<view class="text-lg font-semibold color-428">上传国徽面</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="exam px-15 rounded-sm leading-normal text-dark text-base">
|
||||
身份证示例
|
||||
</view>
|
||||
<view class="mt-12 flex items-center justify-between">
|
||||
<image class="album" src="/static/work/cardFront.png" />
|
||||
<image class="album" src="/static/work/cardBack.png" />
|
||||
</view>
|
||||
<view class="mt-12 text-dark font-semibold text-base">拍摄须知</view>
|
||||
<view class="mt-10 flex items-center justify-between">
|
||||
<view class="flex flex-col items-center justify-center">
|
||||
<image class="mb-5 exam-icon" src="/static/work/fIDCard.png" />
|
||||
<image class="mb-5 status-icon" src="/static/work/hook.png" />
|
||||
<view class="text-base text-dark">标准</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-center justify-center">
|
||||
<image class="mb-5 exam-icon" src="/static/work/lackCard.png" />
|
||||
<image class="mb-5 status-icon" src="/static/work/error.png" />
|
||||
<view class="text-base text-dark">缺边</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-center justify-center">
|
||||
<image class="mb-5 exam-icon" src="/static/work/vagueCard.png" />
|
||||
<image class="mb-5 status-icon" src="/static/work/error.png" />
|
||||
<view class="text-base text-dark">模糊</view>
|
||||
</view>
|
||||
<view class="flex flex-col items-center justify-center">
|
||||
<image class="mb-5 exam-icon" src="/static/work/flashCard.png" />
|
||||
<image class="mb-5 status-icon" src="/static/work/error.png" />
|
||||
<view class="text-base text-dark">闪光</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<template #footer>
|
||||
<button-footer cancelText="上一步" confirmText="提交审核" @confirm="save()" @cancel="back()" />
|
||||
</template>
|
||||
</full-page>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import useGuard from "@/hooks/useGuard.js";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import { upload } from "@/utils/http.js";
|
||||
import { hideLoading, loading as showLoading, toast } from "@/utils/widget";
|
||||
|
||||
import buttonFooter from '@/components/button-footer.vue';
|
||||
import fullPage from '@/components/full-page.vue';
|
||||
|
||||
useGuard();
|
||||
|
||||
const { account, doctorInfo } = storeToRefs(useAccountStore());
|
||||
const form = ref({})
|
||||
const formData = computed(() => ({ ...(doctorInfo.value || {}), ...form.value }))
|
||||
|
||||
function back() {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
function uploadIdCard(type) {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: async (res) => {
|
||||
const [path] = res.tempFilePaths;
|
||||
showLoading('正在上传')
|
||||
const url = await upload(path);
|
||||
hideLoading()
|
||||
if (url) {
|
||||
form.value[type] = url;
|
||||
} else {
|
||||
toast('上传失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (typeof formData.value.idCardFront !== 'string' || formData.value.idCardFront.trim() === '') {
|
||||
return toast('请上传人像面')
|
||||
}
|
||||
if (typeof formData.value.idCardBack !== 'string' || formData.value.idCardBack.trim() === '') {
|
||||
return toast('请上传国徽面')
|
||||
}
|
||||
console.log('form.value: ', formData.value)
|
||||
|
||||
// uni.showToast({ title: '提交成功', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.title-bar {
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
|
||||
.title-bar::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
height: 80%;
|
||||
width: 8rpx;
|
||||
transform: translateY(-50%);
|
||||
border-radius: 4rpx;
|
||||
background: #0074ff;
|
||||
}
|
||||
|
||||
.album {
|
||||
width: 330rpx;
|
||||
height: 200rpx;
|
||||
}
|
||||
|
||||
.carmra-icon {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
}
|
||||
|
||||
.color-428 {
|
||||
color: #428bf0;
|
||||
}
|
||||
|
||||
.exam {
|
||||
margin-top: 80rpx;
|
||||
background: #dde6f6;
|
||||
padding: 8rpx 30rpx;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.exam-icon {
|
||||
width: 160rpx;
|
||||
height: 104rpx;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
</style>
|
||||
126
pages/work/verify/doctor.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<full-page pageClass="bg-white">
|
||||
<view class="p-15">
|
||||
<view class="title-bar relative text-dark text-base font-semibold">请填写执业医院</view>
|
||||
<view class="mt-12 p-10 flex items-center justify-between border rounded">
|
||||
<view class="w-0 flex-grow truncate text-base mr-10" :class="formData.hospitalName ? 'text-dark' : 'text-gray'">
|
||||
{{ formData.hospitalName || '请填写执业医院' }}
|
||||
</view>
|
||||
<uni-icons class="flex-shrink-0" color="#666" type="right" size="16" />
|
||||
</view>
|
||||
<view class="mt-15 title-bar relative font-semibold">
|
||||
<text class="mr-5 text-dark text-base">请上传</text>
|
||||
<text class="text-primary text-base">医师执业资格证</text>
|
||||
</view>
|
||||
<view class="mt-12 flex items-center justify-between">
|
||||
<view class="album border rounded overflow-hidden" @click="uploadLicense('medicalLicenseFront')">
|
||||
<image v-if="formData.medicalLicenseFront" class="w-full h-full" :src="formData.medicalLicenseFront" />
|
||||
<view v-else class="w-full h-full flex flex-col items-center justify-center">
|
||||
<uni-icons color="#666" type="camera" size="36" />
|
||||
<view class="text-dark text-base">上传第一页</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="album border rounded overflow-hidden" @click="uploadLicense('medicalLicenseBack')">
|
||||
<image v-if="formData.medicalLicenseBack" class="w-full h-full" :src="formData.medicalLicenseBack" />
|
||||
<view v-else class="w-full h-full flex flex-col items-center justify-center">
|
||||
<uni-icons color="#666" type="camera" size="36" />
|
||||
<view class="text-dark text-base">上传第二页</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="exam px-15 rounded-sm leading-normal text-dark text-base">
|
||||
证书示例
|
||||
</view>
|
||||
<view class="mt-10 text-sm text-dark leading-normal">1、确保姓名、照片、编号、执业范围、签发机关等清晰可见</view>
|
||||
<view class="mt-10 text-sm text-dark leading-normal">2、需上传证书第一、第二页,图片仅供参考,以实际证书为准</view>
|
||||
<view class="mt-12 flex items-center justify-between">
|
||||
<image class="album" src="/static/work/licenseFront.png" />
|
||||
<image class="album" src="/static/work/licenseBack.png" />
|
||||
</view>
|
||||
</view>
|
||||
<template #footer>
|
||||
<button-footer cancelText="上一步" confirmText="提交审核" @confirm="save()" @cancel="back()" />
|
||||
</template>
|
||||
</full-page>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import useGuard from "@/hooks/useGuard.js";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
import { upload } from "@/utils/http.js";
|
||||
import { hideLoading, loading as showLoading, toast } from "@/utils/widget";
|
||||
|
||||
import buttonFooter from '@/components/button-footer.vue';
|
||||
import fullPage from '@/components/full-page.vue';
|
||||
|
||||
useGuard();
|
||||
const { account, doctorInfo } = storeToRefs(useAccountStore());
|
||||
const form = ref({});
|
||||
const formData = computed(() => ({ ...(doctorInfo.value || {}), ...form.value }))
|
||||
|
||||
function back() {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
function uploadLicense(type) {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: async (res) => {
|
||||
const [path] = res.tempFilePaths;
|
||||
showLoading('正在上传')
|
||||
const url = await upload(path);
|
||||
hideLoading()
|
||||
if (url) {
|
||||
form.value[type] = url;
|
||||
} else {
|
||||
toast('上传失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (typeof formData.value.hospitalName !== 'string' || formData.value.hospitalName.trim() === '') {
|
||||
return toast('请填写执业医院')
|
||||
}
|
||||
if (typeof formData.value.medicalLicenseFront !== 'string' || formData.value.medicalLicenseFront.trim() === '') {
|
||||
return toast('请上传医师执业资格证第一页')
|
||||
}
|
||||
if (typeof formData.value.medicalLicenseBack !== 'string' || formData.value.medicalLicenseBack.trim() === '') {
|
||||
return toast('请上传医师执业资格证第二页')
|
||||
}
|
||||
console.log('form.value: ', formData.value)
|
||||
|
||||
// uni.showToast({ title: '提交成功', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.title-bar {
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
|
||||
.title-bar::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
height: 80%;
|
||||
width: 8rpx;
|
||||
transform: translateY(-50%);
|
||||
border-radius: 4rpx;
|
||||
background: #0074ff;
|
||||
}
|
||||
|
||||
.album {
|
||||
width: 330rpx;
|
||||
height: 240rpx;
|
||||
}
|
||||
|
||||
.exam {
|
||||
margin-top: 80rpx;
|
||||
background: #dde6f6;
|
||||
padding: 8rpx 30rpx;
|
||||
width: fit-content;
|
||||
}
|
||||
</style>
|
||||
@ -1,30 +1,30 @@
|
||||
<template>
|
||||
<view class="work-page">
|
||||
<!-- 顶部用户信息区域 -->
|
||||
<full-page :showSafeArea="false" :customScroll="true">
|
||||
<template #header>
|
||||
<view class="user-header bg-white px-15 py-15">
|
||||
<view class="flex items-center justify-between">
|
||||
<!-- 左侧:用户头像和信息 -->
|
||||
<view class="flex items-center justify-between" @click="editProfile()">
|
||||
<view class="flex items-center flex-grow">
|
||||
<view class="user-avatar mr-10">
|
||||
<image
|
||||
class="avatar-img"
|
||||
src="/static/default-avatar.png"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view class="relative user-avatar mr-10">
|
||||
<image v-if="doctorInfo && doctorInfo.avatar" class="avatar-img rounded-full overflow-hidden"
|
||||
:src="doctorInfo.avatar" mode="aspectFill" />
|
||||
<image v-else class="avatar-img rounded-full overflow-hidden" src="/static/default-avatar.png"
|
||||
mode="aspectFill" />
|
||||
<view v-if="doctorInfo" class="edit-sub flex items-center justify-center rounded-full bg-primary">
|
||||
<image class="edit-icon" src="/static/work/pen.svg" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-col">
|
||||
<text class="user-name text-black text-lg font-semibold"
|
||||
>请完善信息</text
|
||||
>
|
||||
<text v-if="doctorInfo && doctorInfo.anotherName" class="user-name text-dark text-lg font-semibold">
|
||||
{{ doctorInfo.anotherName }}
|
||||
</text>
|
||||
<text v-else class="user-name text-black text-lg font-semibold">请完善信息</text>
|
||||
<view class="flex items-center mt-5">
|
||||
<view
|
||||
class="status-tag tag-orange mr-10"
|
||||
@click="handleCompleteInfo"
|
||||
>
|
||||
<view v-if="!doctorInfo || !doctorInfo.anotherName" class="status-tag tag-orange mr-10">
|
||||
<text class="tag-text text-white">信息待完善</text>
|
||||
</view>
|
||||
<view class="status-tag tag-gray" @click="handleVerify">
|
||||
<text class="tag-text text-dark">未认证</text>
|
||||
<view v-if="certStatus" class="px-10 py-3 text-sm rounded-full" :class="certStatus.classnames"
|
||||
@click.stop="toCert()">
|
||||
{{ certStatus.text }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -32,49 +32,62 @@
|
||||
|
||||
<!-- 右侧:操作按钮 -->
|
||||
<view class="flex items-center">
|
||||
<view
|
||||
class="action-btn flex-col items-center mr-15"
|
||||
@click="handleInvitePatient"
|
||||
>
|
||||
<view class="qrcode-icon">
|
||||
<text class="qrcode-text">▦</text>
|
||||
<view class="action-btn flex-col items-center mr-10" @click="handleInvitePatient">
|
||||
<image class="mb-5 qrcode-icon" src="/static/work/qrcode.svg" />
|
||||
<text class="action-text text-dark text-sm">邀请</text>
|
||||
</view>
|
||||
<text class="action-text text-black text-sm mt-5">邀请患者</text>
|
||||
</view>
|
||||
<view class="more-btn" @click="handleMore">
|
||||
<text class="more-icon">⋯</text>
|
||||
<view class="action-btn flex-col items-center" @click="handleMore">
|
||||
<image class="mb-5 qrcode-icon" src="/static/work/more.svg" />
|
||||
<text class="action-text text-dark text-sm">更多</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 待办列表区域 -->
|
||||
<view class="todo-section px-15 mt-15">
|
||||
<view class="section-title mb-15">
|
||||
<text class="text-black text-lg font-semibold">待办列表11</text>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state">
|
||||
<empty-data text="暂无记录" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-15 px-15 py-12 text-dark text-lg font-semibold bg-white border-b">
|
||||
待办列表11
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<scroll-view v-if="list.length" scroll-y="true" class="h-full bg-white">
|
||||
<view class="p-15">
|
||||
<view v-for="i in 10" class="p-15 bg-primary mb-10"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view v-else class="flex flex-col items-center justify-center h-full bg-white">
|
||||
<empty-data text="暂无记录" />
|
||||
</view>
|
||||
<template #footer>
|
||||
<view class="border-b"></view>
|
||||
</template>
|
||||
</full-page>
|
||||
<cert-popup :visible="visible" @close="visible = false" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { storeToRefs } from "pinia";
|
||||
import useGuard from "@/hooks/useGuard.js";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
|
||||
import certPopup from "./components/cert-popup.vue";
|
||||
import EmptyData from "@/components/empty-data.vue";
|
||||
import fullPage from '@/components/full-page.vue';
|
||||
|
||||
const { useLoad } = useGuard();
|
||||
|
||||
// 完善信息
|
||||
const handleCompleteInfo = () => {
|
||||
uni.navigateTo({
|
||||
url: "/pages/work/profile",
|
||||
});
|
||||
const certConfig = {
|
||||
verified: { text: '已认证', classnames: 'bg-success text-white' },
|
||||
verifing: { text: '认证中', classnames: 'bg-orange text-white' },
|
||||
unverified: { text: '未认证', classnames: 'bg-gray text-dark' },
|
||||
};
|
||||
|
||||
const { useLoad, useShow } = useGuard();
|
||||
const { getDoctorInfo } = useAccountStore();
|
||||
const { doctorInfo } = storeToRefs(useAccountStore());
|
||||
const list = ref([1]);
|
||||
const visible = ref(false);
|
||||
|
||||
const certStatus = computed(() => doctorInfo.value?.verifyStatus ? certConfig[doctorInfo.value.verifyStatus] : certConfig.unverified)
|
||||
|
||||
// 认证
|
||||
const handleVerify = () => {
|
||||
uni.showToast({
|
||||
@ -101,15 +114,39 @@ const handleMore = () => {
|
||||
});
|
||||
};
|
||||
|
||||
function editProfile() {
|
||||
uni.navigateTo({
|
||||
url: "/pages/work/profile",
|
||||
});
|
||||
}
|
||||
|
||||
function toCert() {
|
||||
// if (doctorInfo.value.verifyStatus === 'unverified') {
|
||||
visible.value = true
|
||||
// }
|
||||
}
|
||||
|
||||
useLoad(() => {
|
||||
console.log("工作台页面加载");
|
||||
});
|
||||
|
||||
useShow(() => {
|
||||
getDoctorInfo()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.work-page {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
.edit-sub {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
}
|
||||
|
||||
.user-header {
|
||||
@ -119,9 +156,6 @@ useLoad(() => {
|
||||
.user-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background: #e5e5e5;
|
||||
|
||||
.avatar-img {
|
||||
width: 100%;
|
||||
@ -133,6 +167,11 @@ useLoad(() => {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.py-3 {
|
||||
padding-top: 6rpx;
|
||||
padding-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
@ -162,17 +201,8 @@ useLoad(() => {
|
||||
justify-content: center;
|
||||
|
||||
.qrcode-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.qrcode-text {
|
||||
font-size: 40rpx;
|
||||
color: #333;
|
||||
line-height: 1;
|
||||
}
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
@ -209,5 +239,4 @@ useLoad(() => {
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
// width: 100%;
|
||||
// }
|
||||
</style>
|
||||
// }</style>
|
||||
@ -1,20 +1,40 @@
|
||||
export default [
|
||||
{
|
||||
path: 'pages/message/message',
|
||||
meta: { title: '首页', login: false },
|
||||
style: { navigationStyle: 'custom' }
|
||||
meta: { title: '消息' }
|
||||
},
|
||||
{
|
||||
path: 'pages/message/index',
|
||||
meta: { title: '聊天' },
|
||||
style: { enablePullDownRefresh: false }
|
||||
},
|
||||
{
|
||||
path: 'pages/work/work',
|
||||
meta: { title: '工作台', login: false }
|
||||
meta: { title: '工作台' }
|
||||
},
|
||||
{
|
||||
path: 'pages/case/case',
|
||||
meta: { title: '病例' }
|
||||
},
|
||||
{
|
||||
path: 'pages/work/profile',
|
||||
meta: { title: '完善个人信息', login: false }
|
||||
meta: { title: '完善个人信息' }
|
||||
},
|
||||
{
|
||||
path: 'pages/work/department-select',
|
||||
meta: { title: '选择科室', login: false }
|
||||
}
|
||||
meta: { title: '选择科室' }
|
||||
},
|
||||
{
|
||||
path: 'pages/work/verify/assistant',
|
||||
meta: { title: '上传证照', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/work/verify/doctor',
|
||||
meta: { title: '上传证照', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/login/login',
|
||||
meta: { title: '授权登录' }
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
BIN
static/work/aIDCard.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
static/work/camera.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/work/cardBack.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
static/work/cardFront.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
static/work/error.png
Normal file
|
After Width: | Height: | Size: 960 B |
BIN
static/work/fIDCard.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
static/work/flashCard.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
static/work/hook.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
static/work/lackCard.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
static/work/licenseBack.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
static/work/licenseFront.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
1
static/work/more.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769069890058" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14332" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M378.112 481.536H159.488c-51.2 0-92.928-41.728-92.928-92.928V169.984c0-51.2 41.728-92.928 92.928-92.928h218.624c51.2 0 92.928 41.728 92.928 92.928v218.624c0 51.2-41.728 92.928-92.928 92.928zM159.488 138.752c-17.408 0-31.488 14.08-31.488 31.488v218.624c0 17.408 14.08 31.488 31.488 31.488h218.624c17.408 0 31.488-14.08 31.488-31.488V169.984c0-17.408-14.08-31.488-31.488-31.488H159.488zM378.112 949.504H159.488c-51.2 0-92.928-41.728-92.928-92.928v-218.624c0-51.2 41.728-92.928 92.928-92.928h218.624c51.2 0 92.928 41.728 92.928 92.928v218.624c0 51.456-41.728 92.928-92.928 92.928zM159.488 606.72c-17.408 0-31.488 14.08-31.488 31.488v218.624c0 17.408 14.08 31.488 31.488 31.488h218.624c17.408 0 31.488-14.08 31.488-31.488v-218.624c0-17.408-14.08-31.488-31.488-31.488H159.488zM680.448 480l-143.616-144.128c-33.536-33.792-33.536-88.576 0.256-122.112l144.128-143.616c33.792-33.536 88.576-33.536 122.112 0.256l143.616 144.128c33.536 33.792 33.536 88.576-0.256 122.112l-144.128 143.616c-33.792 33.536-88.32 33.536-122.112-0.256zM762.88 110.848c-11.264-11.52-29.952-11.52-41.216 0l-144.128 143.616c-11.52 11.264-11.52 29.952 0 41.216l143.616 144.128c11.264 11.52 29.952 11.52 41.216 0l144.128-143.616c11.52-11.264 11.52-29.952 0-41.216L762.88 110.848zM840.96 949.504l-218.624-0.512c-51.2 0-92.672-41.728-92.672-92.928l0.512-218.624c0-51.2 41.728-92.672 92.928-92.672l218.624 0.512c51.2 0 92.672 41.728 92.672 92.928l-0.512 218.624c0 51.2-41.728 92.928-92.928 92.672z m-217.856-343.04c-17.408 0-31.488 14.08-31.488 31.232l-0.512 218.624c0 17.408 14.08 31.488 31.232 31.488l218.624 0.512c17.408 0 31.488-14.08 31.488-31.232l0.512-218.624c0-17.408-14.08-31.488-31.232-31.488l-218.624-0.512z" fill="#2c2c2c" p-id="14333"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
1
static/work/pen.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769067872142" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10445" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M581.50172 186.48l256.04 256.04-555.98 555.98-228.28 25.2C22.72172 1027.08-3.09828 1001.24 0.30172 970.68l25.4-228.44 555.8-555.76z m414.4-38.12l-120.22-120.22c-37.5-37.5-98.32-37.5-135.82 0l-113.1 113.1 256.04 256.04 113.1-113.1c37.5-37.52 37.5-98.32 0-135.82z" fill="#ffffff" p-id="10446"></path></svg>
|
||||
|
After Width: | Height: | Size: 638 B |
1
static/work/qrcode.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769069475491" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11505" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M85.312 85.312V384H384V85.312H85.312zM0 0h469.248v469.248H0V0z m170.624 170.624h128v128h-128v-128zM0 554.624h469.248v469.248H0V554.624z m85.312 85.312v298.624H384V639.936H85.312z m85.312 85.312h128v128h-128v-128zM554.624 0h469.248v469.248H554.624V0z m85.312 85.312V384h298.624V85.312H639.936z m383.936 682.56H1024v85.376h-298.752V639.936H639.936V1023.872H554.624V554.624h255.936v213.248h128V554.624h85.312v213.248z m-298.624-597.248h128v128h-128v-128z m298.624 853.248h-85.312v-85.312h85.312v85.312z m-213.312 0h-85.312v-85.312h85.312v85.312z" fill="#262626" p-id="11506"></path></svg>
|
||||
|
After Width: | Height: | Size: 919 B |
BIN
static/work/vagueCard.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
@ -8,17 +8,28 @@ const env = __VITE_ENV__;
|
||||
|
||||
export default defineStore("accountStore", () => {
|
||||
const appid = env.MP_WX_APP_ID;
|
||||
const corpId = env.MP_CORP_ID;
|
||||
const account = ref(null);
|
||||
const loading = ref(false)
|
||||
const loading = ref(false);
|
||||
const loginPromise = ref(null);
|
||||
// IM 相关
|
||||
const openid = ref("");
|
||||
const isIMInitialized = ref(false);
|
||||
// 医生信息
|
||||
const doctorInfo = ref(null);
|
||||
|
||||
async function login(phoneCode = '') {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
function getLoginPromise(phoneCode = '') {
|
||||
if (loginPromise.value) return loginPromise.value;
|
||||
loginPromise.value = loginByCode(phoneCode);
|
||||
return loginPromise.value;
|
||||
}
|
||||
|
||||
async function login(phoneCode) {
|
||||
await getLoginPromise(phoneCode);
|
||||
loginPromise.value = null;
|
||||
}
|
||||
|
||||
async function loginByCode(phoneCode = '') {
|
||||
try {
|
||||
const { code } = await uni.login({
|
||||
appid,
|
||||
@ -29,8 +40,8 @@ export default defineStore("accountStore", () => {
|
||||
const res = await api('wxAppLogin', {
|
||||
phoneCode,
|
||||
code,
|
||||
corpId,
|
||||
});
|
||||
loading.value = false;
|
||||
if (res.success && res.data) {
|
||||
if (!res.data.mobile) {
|
||||
const target = '/pages/login/login';
|
||||
@ -39,8 +50,6 @@ export default defineStore("accountStore", () => {
|
||||
}
|
||||
account.value = res.data;
|
||||
openid.value = res.data.openid;
|
||||
|
||||
|
||||
// 登录成功后初始化腾讯IM
|
||||
try {
|
||||
console.log('开始初始化腾讯IM,userID:', res.data.openid);
|
||||
@ -56,10 +65,11 @@ export default defineStore("accountStore", () => {
|
||||
}
|
||||
}
|
||||
toast('登录失败,请重新登录');
|
||||
|
||||
} catch (e) {
|
||||
toast('登录失败,请重新登录');
|
||||
}
|
||||
loading.value = false
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
async function getDoctorInfo() {
|
||||
|
||||
@ -11,7 +11,9 @@ const urlsConfig = {
|
||||
getHospitalList: 'getRealHospital',
|
||||
addCorpMember: 'addCorpMember',
|
||||
getCorpMemberData: 'getCorpMemberData',
|
||||
updateCorpMember: 'updateCorpMember'
|
||||
updateCorpMember: 'updateCorpMember',
|
||||
addCorpMemberFromWxapp: "addCorpMemberFromWxapp",
|
||||
updateCorpMemberFromWxapp: "updateCorpMemberFromWxapp"
|
||||
},
|
||||
|
||||
knowledgeBase: {
|
||||
|
||||
@ -206,5 +206,28 @@ export default request;
|
||||
export const uploadUrl = `${baseUrl}/upload`;
|
||||
|
||||
export function getFullPath(path) {
|
||||
return `${baseUrl}${path}`;
|
||||
return `${baseUrl}/${path}`;
|
||||
}
|
||||
|
||||
export function upload(path) {
|
||||
return new Promise((resolve) => {
|
||||
uni.uploadFile({
|
||||
url: uploadUrl, // 替换为你的上传接口地址
|
||||
filePath: path,
|
||||
name: 'file',
|
||||
fileType: 'image',
|
||||
success: (res) => {
|
||||
try {
|
||||
const url = JSON.parse(res.data).filePath;
|
||||
resolve(url ? getFullPath(url) : '')
|
||||
} catch (e) {
|
||||
resolve()
|
||||
}
|
||||
},
|
||||
fail: res => {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||