diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..4b5a015
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,10 @@
+MP_API_BASE_URL=https://ytk.youcan365.com
+MP_IMAGE_URL=https://ytk.youcan365.com
+MP_CACHE_PREFIX=production
+MP_WX_APP_ID=wx1d8337a40c11d66c
+MP_CORP_ID=wpLgjyawAA8N0gWmXgyJq8wpjGcOT7fg
+MP_TIM_SDK_APP_ID=1600123876
+MP_INVITE_TEAMMATE_QRCODE=https://ykt.youcan365.com/invite-teammate
+MP_INVITE_PATIENT_QRCODE=https://ykt.youcan365.com/invite-patient
+MP_PATIENT_PAGE_BASE_URL= 'https://www.youcan365.com/h5/#/'
+MP_SURVEY_URL= 'https://www.youcan365.com/surveyDev/#/pages/survey/survey'
diff --git a/components/form-template/cell-style.css b/components/form-template/cell-style.css
index 999e2e2..80a95d6 100644
--- a/components/form-template/cell-style.css
+++ b/components/form-template/cell-style.css
@@ -11,6 +11,11 @@
top: 0;
}
+.form-cell-required {
+ margin-left: 4rpx;
+ color: #ff4d4f;
+}
+
.form-content__wrapper {
width: 100%;
display: flex;
@@ -58,4 +63,4 @@
.form-row__content {
width: 0;
flex-grow: 1;
-}
\ No newline at end of file
+}
diff --git a/components/form-template/common-cell.vue b/components/form-template/common-cell.vue
index 301a120..34ea433 100644
--- a/components/form-template/common-cell.vue
+++ b/components/form-template/common-cell.vue
@@ -1,7 +1,7 @@
- {{ name }}
+ {{ name }}*
diff --git a/components/form-template/form-cell/form-files.vue b/components/form-template/form-cell/form-files.vue
index ff9afaf..0ce6b67 100644
--- a/components/form-template/form-cell/form-files.vue
+++ b/components/form-template/form-cell/form-files.vue
@@ -1,6 +1,8 @@
- {{ name }}
+
+ {{ name }}*
+
@@ -15,7 +17,7 @@
diff --git a/pages/case/archive-detail.vue b/pages/case/archive-detail.vue
index e5766e8..e8a8a0f 100644
--- a/pages/case/archive-detail.vue
+++ b/pages/case/archive-detail.vue
@@ -2,18 +2,12 @@
-
-
diff --git a/pages/case/patient-inner-info.vue b/pages/case/patient-inner-info.vue
index 8fd86c1..328e394 100644
--- a/pages/case/patient-inner-info.vue
+++ b/pages/case/patient-inner-info.vue
@@ -267,6 +267,12 @@ function isTagItem(i) {
return title === 'tagIds' || title === 'tag' || type === 'tag' || name.includes('标签');
}
+function isInHospitalSourceItem(i) {
+ const title = String(i?.title || '');
+ const name = String(i?.name || '');
+ return title === 'inHospitalSource' || title === 'hospitalSource' || name.includes('院内来源');
+}
+
async function loadInternalTemplate() {
const corpId = String(account.value?.corpId || doctorInfo.value?.corpId || '') || '';
if (!corpId) return;
@@ -304,6 +310,7 @@ async function loadInternalTemplate() {
items.value = list
.filter((i) => i && i.fieldStatus !== 'disable')
.filter((i) => i.operateType !== 'onlyRead')
+ .filter((i) => !isInHospitalSourceItem(i))
.map(normalizeTemplateItem);
const debugStage = items.value.find(isStageItem);
@@ -392,6 +399,20 @@ function buildPayload(base, inner) {
return { payload, team };
}
+function getCreatedCustomerId(res) {
+ const root = res && typeof res === 'object' ? res : {};
+ const d = root.data && typeof root.data === 'object' ? root.data : {};
+ return String(
+ d._id ||
+ d.id ||
+ d.customerId ||
+ d.memberId ||
+ root.customerId ||
+ root.memberId ||
+ ''
+ ) || '';
+}
+
async function save() {
if (formRef.value?.verify && !formRef.value.verify()) return;
@@ -420,10 +441,23 @@ async function save() {
}
toast('新增成功');
+ const createdId = getCreatedCustomerId(res);
uni.removeStorageSync(BASE_KEY);
uni.removeStorageSync(INNER_KEY);
uni.setStorageSync(NEED_RELOAD_STORAGE_KEY, 1);
- uni.navigateBack({ delta: 2 });
+ uni.navigateBack({
+ delta: 2,
+ success: () => {
+ if (!createdId) return;
+ setTimeout(() => {
+ uni.navigateTo({ url: `/pages/case/archive-detail?id=${encodeURIComponent(createdId)}` });
+ }, 30);
+ },
+ fail: () => {
+ if (!createdId) return;
+ uni.redirectTo({ url: `/pages/case/archive-detail?id=${encodeURIComponent(createdId)}` });
+ },
+ });
} catch (e) {
hideLoading();
toast('新增失败');
diff --git a/pages/case/service-record-detail.vue b/pages/case/service-record-detail.vue
index cf686e3..6fe1b31 100644
--- a/pages/case/service-record-detail.vue
+++ b/pages/case/service-record-detail.vue
@@ -1,7 +1,7 @@
-
+
执行日期
@@ -31,12 +31,11 @@
所属团队
-
-
+
+
{{ currentTeam?.value ? currentTeam.label : '请选择所属团队' }}
-
@@ -55,14 +54,37 @@
-
-
-
+
+
+
+
+
+
+
+ {{ (form.taskContent || '').length }}/1000
+
+
+
+
+
diff --git a/pages/case/utils/template.js b/pages/case/utils/template.js
new file mode 100644
index 0000000..d7cbc57
--- /dev/null
+++ b/pages/case/utils/template.js
@@ -0,0 +1,94 @@
+function normalizeOptions(options) {
+ if (!Array.isArray(options)) return [];
+ if (!options.length) return [];
+ if (typeof options[0] === 'string') return options.filter((i) => typeof i === 'string');
+ if (typeof options[0] === 'object') {
+ return options
+ .map((i) => {
+ const label = i?.label ?? i?.name ?? i?.text ?? i?.title ?? '';
+ const value = i?.value ?? i?.id ?? i?.key ?? label;
+ if (!label && (value === undefined || value === null || value === '')) return null;
+ return { label: String(label || value), value: String(value) };
+ })
+ .filter(Boolean);
+ }
+ return [];
+}
+
+export function normalizeTemplateItem(item) {
+ const next = { ...(item || {}) };
+
+ if (next.operateType === 'custom') next.operateType = 'formCell';
+
+ const originalType = next.type;
+ const customTypeMap = {
+ customerSource: 'select',
+ customerStage: 'select',
+ tag: 'multiSelectAndOther',
+ reference: 'input',
+ selectWwuser: 'select',
+ files: 'files',
+ corpProject: 'select',
+ diagnosis: 'diagnosis',
+ BMI: 'input',
+ bloodPressure: 'textarea',
+ selfMultipleDiseases: 'textarea',
+ };
+ if (originalType && customTypeMap[originalType]) {
+ next.__originType = originalType;
+ next.type = customTypeMap[originalType];
+ }
+
+ const aliasTypeMap = {
+ text: 'input',
+ string: 'input',
+ number: 'input',
+ integer: 'input',
+ int: 'input',
+ };
+ if (next.type && aliasTypeMap[next.type]) {
+ next.type = aliasTypeMap[next.type];
+ if (!next.inputType && (originalType === 'number' || originalType === 'integer' || originalType === 'int')) next.inputType = 'number';
+ }
+
+ const rawRange = next.range || next.options || next.optionList || next.values || [];
+ const range = normalizeOptions(rawRange);
+
+ if (next.type === 'select' || next.type === 'selectAndOther' || next.type === 'selectAndImage') {
+ next.range = range;
+ } else if (next.type === 'radio') {
+ // wxapp 目前 radio 组件只支持字符串列表;模板如为对象选项则降级为 select
+ if (range.length && typeof range[0] === 'object') {
+ next.type = 'select';
+ next.range = range;
+ } else {
+ next.range = Array.isArray(rawRange) ? rawRange : [];
+ }
+ }
+
+ if (!next.operateType) next.operateType = 'formCell';
+ next.required = Boolean(next.required);
+
+ if (next.type === 'input' && (next.wordLimit === undefined || next.wordLimit === null || next.wordLimit === '')) next.wordLimit = 20;
+ if (next.type === 'textarea' && (next.wordLimit === undefined || next.wordLimit === null || next.wordLimit === '')) next.wordLimit = 200;
+ return next;
+}
+
+export function unwrapTemplateResponse(res) {
+ const d = res?.data;
+ if (d && typeof d === 'object') {
+ if (d.data && typeof d.data === 'object') return d.data;
+ return d;
+ }
+ return res && typeof res === 'object' ? res : {};
+}
+
+export function normalizeTemplate(temp) {
+ const t = temp && typeof temp === 'object' ? { ...temp } : {};
+ const list = Array.isArray(t.templateList) ? t.templateList : [];
+ t.templateList = list
+ .filter((i) => i && i.fieldStatus !== 'disable')
+ .filter((i) => i.operateType !== 'onlyRead')
+ .map(normalizeTemplateItem);
+ return t;
+}
diff --git a/pages/case/utils/visit-record.js b/pages/case/utils/visit-record.js
new file mode 100644
index 0000000..721c1ef
--- /dev/null
+++ b/pages/case/utils/visit-record.js
@@ -0,0 +1,40 @@
+function isEmpty(v) {
+ if (v === null || v === undefined) return true;
+ if (Array.isArray(v)) return v.length === 0;
+ if (typeof v === 'string') return v.trim() === '';
+ return false;
+}
+
+const ALIAS_MAP = {
+ outpatient: {
+ diagnosisName: 'diagnosis',
+ medicalHistorySummary: 'medicalHistory',
+ },
+ inhospital: {
+ diagnosisName: 'diagnosis',
+ medicalHistorySummary: 'medicalHistory',
+ operationDate: 'surgeryDate',
+ operation: 'surgeryName',
+ },
+ physicalExaminationTemplate: {
+ inspectTime: 'inspectDate',
+ inspectSummary: 'summary',
+ },
+ preConsultation: {
+ presentIllnessHistory: 'presentIllness',
+ pastMedicalHistory: 'pastHistory',
+ },
+};
+
+export function normalizeVisitRecordFormData(templateType, raw) {
+ const input = raw && typeof raw === 'object' ? raw : {};
+ const out = { ...input };
+ const map = ALIAS_MAP[String(templateType || '')] || {};
+
+ Object.entries(map).forEach(([from, to]) => {
+ if (isEmpty(out[to]) && !isEmpty(out[from])) out[to] = out[from];
+ });
+
+ return out;
+}
+
diff --git a/pages/case/visit-record-detail.vue b/pages/case/visit-record-detail.vue
index 0c283cd..ad07c2e 100644
--- a/pages/case/visit-record-detail.vue
+++ b/pages/case/visit-record-detail.vue
@@ -3,29 +3,8 @@
-
-
-
-
-
-
-
-
- 文件上传
- (支持≤5M文件,pdf文件格式)
-
-
-
-
- ×
-
-
- +
-
-
+
@@ -49,10 +28,11 @@ import { onLoad } from '@dcloudio/uni-app';
import dayjs from 'dayjs';
import { storeToRefs } from 'pinia';
import FormTemplate from '@/components/form-template/index.vue';
-import { getVisitRecordTemplate } from './components/archive-detail/templates';
import api from '@/utils/api';
import useAccountStore from '@/store/account';
import { toast, confirm, loading as uniLoading, hideLoading } from '@/utils/widget';
+import { normalizeVisitRecordFormData } from './utils/visit-record';
+import { normalizeTemplate, unwrapTemplateResponse } from './utils/template';
const accountStore = useAccountStore();
const { account, doctorInfo } = storeToRefs(accountStore);
@@ -84,17 +64,43 @@ function getCorpId() {
const memberId = ref('');
const recordId = ref('');
const templateType = ref('');
-const customerName = ref('');
-const template = computed(() => getVisitRecordTemplate(templateType.value));
+const temp = ref(null);
+const titleText = computed(() => {
+ const t = temp.value || {};
+ return String(t.name || t.templateName || t.templateTypeName || '').trim();
+});
const detail = ref({});
const form = reactive({});
const forms = computed(() => ({ ...detail.value, ...form }));
+const HIDDEN_FIELD_NAMES = {
+ outpatient: ['就诊机构', '就诊科室', '机构名称', '责任医生'],
+ inhospital: ['就诊机构', '机构名称'],
+};
+const HIDDEN_FIELD_TITLES = {
+ // 对应 systemFieldName/title(来自模板):
+ // - 就诊机构: corp
+ // - 就诊科室: deptName
+ // - 机构名称: corpName
+ // - 责任医生: doctor
+ outpatient: ['corp', 'deptName', 'corpName', 'doctor'],
+ // - 就诊机构: corp
+ // - 机构名称: corpName
+ inhospital: ['corp', 'corpName'],
+};
+function shouldHideField(item) {
+ const t = String(templateType.value || '');
+ const name = item?.name ? String(item.name).trim() : '';
+ const title = item?.title ? String(item.title).trim() : '';
+ const hiddenNames = HIDDEN_FIELD_NAMES[t] || [];
+ const hiddenTitles = HIDDEN_FIELD_TITLES[t] || [];
+ return (name && hiddenNames.includes(name)) || (title && hiddenTitles.includes(title));
+}
const showItems = computed(() => {
- const list = template.value?.templateList || [];
+ const list = temp.value?.templateList || [];
// referenceField 兼容(与 mobile 一致)
return list.filter((i) => {
- if (i?.type === 'files') return false;
+ if (shouldHideField(i)) return false;
if (i && typeof i.referenceField === 'string') {
return forms.value[i.referenceField] === i.referenceValue;
}
@@ -102,16 +108,7 @@ const showItems = computed(() => {
});
});
-const hasFilesField = computed(() => {
- const list = template.value?.templateList || [];
- return list.some((i) => i && (i.type === 'files' || i.title === 'files'));
-});
-
const formRef = ref(null);
-const fileList = computed(() => {
- const arr = forms.value?.files;
- return Array.isArray(arr) ? arr.filter((i) => i && i.url) : [];
-});
function ensureFilesField() {
if (form.files !== undefined) return;
@@ -119,30 +116,43 @@ function ensureFilesField() {
form.files = [];
}
+async function loadTemplate(t) {
+ const corpId = getCorpId();
+ if (!corpId) return null;
+ try {
+ const res = await api('getCurrentTemplate', { corpId, templateType: t });
+ if (!res?.success) {
+ toast(res?.message || '获取模板失败');
+ return null;
+ }
+ const raw = unwrapTemplateResponse(res);
+ return normalizeTemplate(raw);
+ } catch (e) {
+ console.error('loadTemplate error:', e);
+ toast('获取模板失败');
+ return null;
+ }
+}
+
onLoad(async (options) => {
memberId.value = options?.memberId || options?.archiveId || '';
recordId.value = options?.id || '';
templateType.value = options?.type || '';
- customerName.value = decodeURIComponent(options?.customerName || '');
if (recordId.value) {
await getDetail();
} else {
if (!templateType.value) templateType.value = 'outpatient';
+ temp.value = await loadTemplate(templateType.value);
+ if (temp.value?.templateType) templateType.value = String(temp.value.templateType);
ensureFilesField();
- // 门诊记录默认今日日期
- if (templateType.value === 'outpatient') {
- form.visitTime = dayjs().format('YYYY-MM-DD');
- }
- // 住院记录默认今日日期
- if (templateType.value === 'inhospital') {
- form.inhosDate = dayjs().format('YYYY-MM-DD');
- }
- // 体检记录默认今日日期
- if (templateType.value === 'physicalExaminationTemplate') {
- form.inspectDate = dayjs().format('YYYY-MM-DD');
- }
+
+ // 默认填充模板时间字段
+ const timeKey = temp.value?.service?.timeTitle || '';
+ if (timeKey && !form[timeKey]) form[timeKey] = dayjs().format('YYYY-MM-DD');
}
+
+ if (titleText.value) uni.setNavigationBarTitle({ title: titleText.value });
});
async function getDetail() {
@@ -162,14 +172,14 @@ async function getDetail() {
const record = res?.record || res?.data?.record || null;
if (res?.success && record) {
templateType.value = record.templateType || record.medicalType || templateType.value;
-
- // 兼容模板字段:wxapp 使用 diagnosis,但接口通常返回 diagnosisName
- if ((record.medicalType === 'outpatient' || record.medicalType === 'inhospital') && !record.diagnosis && record.diagnosisName) {
- record.diagnosis = record.diagnosisName;
- }
-
- detail.value = record;
+ detail.value = normalizeVisitRecordFormData(templateType.value, record);
ensureFilesField();
+ // 详情可能返回真实 templateType:与模板保持一致
+ if (!temp.value || temp.value?.templateType !== templateType.value) {
+ temp.value = await loadTemplate(templateType.value);
+ if (temp.value?.templateType) templateType.value = String(temp.value.templateType);
+ if (titleText.value) uni.setNavigationBarTitle({ title: titleText.value });
+ }
} else {
toast(res.message || '加载失败');
}
@@ -185,7 +195,7 @@ function onChange({ title, value }) {
const item = showItems.value.find((i) => i.title === title);
if (!item) return;
// 关联字段变化时清理被关联字段(与 mobile 行为一致)
- const relat = (template.value?.templateList || []).filter((i) => i.referenceField === title);
+ const relat = (temp.value?.templateList || []).filter((i) => i.referenceField === title);
relat.forEach((i) => (form[i.title] = ''));
}
@@ -224,7 +234,7 @@ async function save() {
}
// sortTime:使用模板中的时间字段
- const sortTimeKey = template.value?.service?.timeTitle || '';
+ const sortTimeKey = temp.value?.service?.timeTitle || '';
if (sortTimeKey && form[sortTimeKey] && dayjs(form[sortTimeKey]).isValid()) {
params.sortTime = dayjs(form[sortTimeKey]).valueOf();
} else {
@@ -252,76 +262,39 @@ async function save() {
}
}
-function remove() {
- confirm('确定删除当前记录?', async () => {
- if (!memberId.value || !recordId.value) return toast('缺少必要信息');
- await ensureDoctor();
- const corpId = getCorpId();
- if (!corpId) return toast('缺少必要信息');
- uniLoading('删除中...');
- try {
- const res = await api('removeMedicalRecord', {
- corpId,
- memberId: memberId.value,
- medicalType: templateType.value,
- _id: recordId.value,
- });
- hideLoading();
- if (res.success) {
- uni.$emit('archive-detail:visit-record-changed');
- toast(res.message || '已删除');
- setTimeout(() => uni.navigateBack(), 300);
- } else {
- toast(res.message || '删除失败');
- }
- } catch (error) {
- hideLoading();
- console.error('remove error:', error);
- toast('删除失败');
+async function remove() {
+ try {
+ await confirm('确定删除当前记录?');
+ } catch {
+ return;
+ }
+ if (!memberId.value || !recordId.value) return toast('缺少必要信息');
+ await ensureDoctor();
+ const corpId = getCorpId();
+ if (!corpId) return toast('缺少必要信息');
+ uniLoading('删除中...');
+ try {
+ const res = await api('removeMedicalRecord', {
+ corpId,
+ memberId: memberId.value,
+ medicalType: templateType.value,
+ _id: recordId.value,
+ });
+ hideLoading();
+ if (res.success) {
+ uni.$emit('archive-detail:visit-record-changed');
+ toast(res.message || '已删除');
+ setTimeout(() => uni.navigateBack(), 300);
+ } else {
+ toast(res.message || '删除失败');
}
- });
+ } catch (error) {
+ hideLoading();
+ console.error('remove error:', error);
+ toast('删除失败');
+ }
}
-function addFiles() {
- const fileConfig = template.value?.templateList?.find(i => i.type === 'files');
- const maxSize = fileConfig?.maxSize || 5; // MB
- const accept = fileConfig?.accept || 'pdf';
-
- uni.chooseMessageFile({
- count: 9,
- type: 'file',
- extension: [accept],
- success: (res) => {
- const files = Array.isArray(res.tempFiles) ? res.tempFiles : [];
- const maxBytes = maxSize * 1024 * 1024;
-
- // 验证文件大小
- const invalidFiles = files.filter(f => f.size > maxBytes);
- if (invalidFiles.length > 0) {
- toast(`文件大小不能超过${maxSize}M`);
- return;
- }
-
- const next = files.map((f) => ({
- url: f.path,
- name: f.name || '',
- size: f.size
- }));
- const cur = Array.isArray(forms.value.files) ? forms.value.files : [];
- form.files = [...cur, ...next];
- },
- });
-}
-
-function removeFile(idx) {
- const cur = Array.isArray(forms.value.files) ? forms.value.files : [];
- form.files = cur.filter((_, i) => i !== idx);
-}
-
-function previewFile(idx) {
- const urls = fileList.value.map((i) => i.url);
- uni.previewImage({ urls, current: urls[idx] });
-}
\ No newline at end of file
+.load-more-text {
+ font-size: 24rpx;
+ color: #999;
+}
+
diff --git a/pages/library/diagnosis-list.vue b/pages/library/diagnosis-list.vue
index 00846e5..c5b6148 100644
--- a/pages/library/diagnosis-list.vue
+++ b/pages/library/diagnosis-list.vue
@@ -9,7 +9,7 @@
{{ item.label }}
- 暂无诊断数据
+ {{ keyword.trim() ? '暂无诊断数据' : '请输入关键词搜索' }}
@@ -31,6 +31,7 @@ const list = ref([]);
const selections = ref([]);
const mult = ref(false);
const eventName = ref('change-diagnosis');
+let lastQueryId = 0;
const selectedMap = computed(() => selections.value.reduce((m, i) => ((m[i] = true), m), {}));
@@ -38,22 +39,8 @@ function normalizeText(v) {
return v ? String(v) : '';
}
-const fullMatched = computed(() => {
- const value = String(keyword.value || '').trim();
- if (!value) return null;
- return { label: value, value, key: `full_${value}` };
-});
-
const showList = computed(() => {
- const base = Array.isArray(list.value) ? list.value : [];
- const arr = [];
- if (fullMatched.value) arr.push(fullMatched.value);
- base.forEach((i) => {
- if (!i || !i.label) return;
- if (fullMatched.value && i.label === fullMatched.value.label) return;
- arr.push(i);
- });
- return arr;
+ return Array.isArray(list.value) ? list.value : [];
});
let timer = null;
@@ -89,11 +76,25 @@ onLoad((opt) => {
async function query() {
if (!ready.value) return;
const value = String(keyword.value || '').trim();
+ if (!value) {
+ list.value = [];
+ return;
+ }
+
+ const queryId = ++lastQueryId;
- uni.showLoading({ title: '加载中...' });
try {
+ uni.showLoading({ title: '加载中...' });
const res = await api('getDisease', { diseaseName: value });
- const arr = Array.isArray(res?.data?.data) ? res.data.data : [];
+ if (queryId !== lastQueryId) return;
+ const arr =
+ Array.isArray(res?.data?.data) ? res.data.data
+ : Array.isArray(res?.data?.list) ? res.data.list
+ : Array.isArray(res?.data?.data?.data) ? res.data.data.data
+ : Array.isArray(res?.data) ? res.data
+ : Array.isArray(res?.list) ? res.list
+ : Array.isArray(res?.data?.data?.list) ? res.data.data.list
+ : [];
list.value = arr
.map((i) => {
const label = normalizeText(i?.diseaseName);
@@ -103,9 +104,9 @@ async function query() {
})
.filter(Boolean);
} catch (e) {
- list.value = [];
+ if (queryId === lastQueryId) list.value = [];
} finally {
- uni.hideLoading();
+ if (queryId === lastQueryId) uni.hideLoading();
}
}
diff --git a/pages/login/login.vue b/pages/login/login.vue
index a994e3c..d2eac72 100644
--- a/pages/login/login.vue
+++ b/pages/login/login.vue
@@ -5,7 +5,13 @@
全周期健康管理伙伴
-
+
+
+
\ No newline at end of file
+.load-more-text {
+ font-size: 24rpx;
+ color: #999;
+}
+
diff --git a/pages/work/team/invite/invite-teammate.vue b/pages/work/team/invite/invite-teammate.vue
index 73ad092..363b906 100644
--- a/pages/work/team/invite/invite-teammate.vue
+++ b/pages/work/team/invite/invite-teammate.vue
@@ -1,118 +1,141 @@
-
-
-
-
- {{ team.name }}
-
-
- 成员邀请码
-
-
-
-
-
- 微信扫一扫上面的二维码
-
-
- 加入我的团队,协同开展患者管理服务
-
-
-
- 保存图片
-
- 分享微信
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/store/account.js b/store/account.js
index eb46acb..82d41d9 100644
--- a/store/account.js
+++ b/store/account.js
@@ -41,6 +41,7 @@ export default defineStore("accountStore", () => {
async function loginByCode(phoneCode = '') {
try {
+
const { code } = await uni.login({
appid,
provider: "weixin",
@@ -61,13 +62,12 @@ export default defineStore("accountStore", () => {
}
account.value = res.data;
openid.value = res.data.openid;
-
// 持久化账户信息
cache.set(CACHE_KEYS.ACCOUNT, res.data);
cache.set(CACHE_KEYS.OPENID, res.data.openid);
// 登录成功后初始化腾讯IM
- await getDoctorInfo(openid.value);
+ await getDoctorInfo({ openid: openid.value });
await initIMAfterLogin();
return res.data
}
@@ -109,8 +109,7 @@ export default defineStore("accountStore", () => {
async function initIMAfterLogin() {
if (isIMInitialized.value) return true;
if (!doctorInfo.value) {
- console.error('医生信息未获取,无法初始化IM');
- return false;
+ await getDoctorInfo();
}
try {
const userID = doctorInfo.value.userid;
@@ -120,13 +119,13 @@ export default defineStore("accountStore", () => {
throw new Error('无法获取用户ID');
}
}
-
+
const success = await initGlobalTIM(userID);
if (!success) {
console.error('initGlobalTIM 返回失败');
return false;
}
-
+
isIMInitialized.value = true;
return true;
} catch (error) {
diff --git a/utils/api.js b/utils/api.js
index a2b8ac2..18a53f9 100644
--- a/utils/api.js
+++ b/utils/api.js
@@ -10,6 +10,8 @@ const urlsConfig = {
getTeamData: 'getTeamData',
getTeamBymember: 'getTeamBymember',
getCurrentTemplate: 'getCurrentTemplate',
+ getTemplateGroup: 'getTemplateGroup',
+ getTemplateListByTemptype: 'getTemplateListByTemptype',
wxAppLogin: 'wxAppLogin',
getDeptList: 'getRealDeptList',
getHospitalList: 'getRealHospital',
diff --git a/utils/file.js b/utils/file.js
index 232beff..314bedb 100644
--- a/utils/file.js
+++ b/utils/file.js
@@ -1,10 +1,39 @@
const env = __VITE_ENV__;
+function joinBaseAndPath(base, path) {
+ const b = String(base || '').replace(/\/+$/, '');
+ const p = String(path || '');
+ if (!p) return b;
+ if (/^https?:\/\//i.test(p)) return p;
+ return `${b}/${p.replace(/^\/+/, '')}`;
+}
+
+// 兼容历史数据:某些链接缺少域名后的 /
+export function normalizeFileUrl(url) {
+ const u = String(url || '').trim();
+ if (!u) return '';
+ if (/^https?:\/\//i.test(u)) {
+ const afterProtocolIndex = u.indexOf('://') + 3;
+ const firstSlashIndex = u.indexOf('/', afterProtocolIndex);
+ if (firstSlashIndex > 0) {
+ const prefix = u.slice(0, afterProtocolIndex);
+ const host = u.slice(afterProtocolIndex, firstSlashIndex);
+ const path = u.slice(firstSlashIndex);
+ if (host.toLowerCase().endsWith('uploads') && !path.toLowerCase().startsWith('/uploads/')) {
+ const fixedHost = host.slice(0, -'uploads'.length);
+ const normalizedPath = `/uploads${path.startsWith('/') ? '' : '/'}${path.replace(/^\/+/, '')}`;
+ return `${prefix}${fixedHost}${normalizedPath}`;
+ }
+ }
+ }
+ return u.replace(/^(https?:\/\/[^/]+)(uploads\/)/i, '$1/$2');
+}
+
export async function uploadFile(tempFilePath) {
try {
const res = await new Promise((resolve, reject) => {
uni.uploadFile({
- url: `${env.MP_API_BASE_URL}/upload`,
+ url: joinBaseAndPath(env.MP_API_BASE_URL, 'upload'),
filePath: tempFilePath,
name: 'file',
success: (resp) => resolve(resp),
@@ -14,7 +43,7 @@ export async function uploadFile(tempFilePath) {
const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
if (data && data.success && data.filePath) {
- return `${env.MP_API_BASE_URL}${data.filePath}`;
+ return normalizeFileUrl(joinBaseAndPath(env.MP_API_BASE_URL, data.filePath));
}
} catch (e) {
console.log('upload file error:', e);
@@ -58,5 +87,3 @@ export async function chooseAndUploadImage(options = {}) {
return null;
}
}
-
-
diff --git a/utils/send-message-helper.js b/utils/send-message-helper.js
index 0c86122..01bc69a 100644
--- a/utils/send-message-helper.js
+++ b/utils/send-message-helper.js
@@ -283,7 +283,6 @@ function generateSendLink(survey, answerId, customerId, customerName, sendSurvey
const { corpId, userId } = context;
const isSystem = survey.createBy === 'system';
let url = '';
- debugger
if (isSystem) {
// 系统问卷:使用 VITE_SURVEY_URL
url = `${env?.MP_SURVEY_URL}?corpId=${corpId}&surveryId=${survey.surveryId}&memberId=${customerId}&sendSurveyId=${sendSurveyId}&userId=${userId}`;
@@ -359,6 +358,7 @@ export async function handleFollowUpMessages(messages, context = {}) {
corpId: context.corpId,
});
} else if (msg.type === 'questionnaire') {
+
success = await sendSurveyMessage(msg.content, {
userId: context.userId,
customerId: context.customerId,
diff --git a/utils/tim-chat.js b/utils/tim-chat.js
index cd88a20..14d8ed4 100644
--- a/utils/tim-chat.js
+++ b/utils/tim-chat.js
@@ -1030,6 +1030,13 @@ class TimChatManager {
// 获取群聊列表
getGroupList() {
return new Promise((resolve, reject) => {
+ // 检查userId是否存在,不存在则不需要初始化
+ if (!this.currentUserID) {
+ console.error('currentUserID不存在,无法获取群聊列表')
+ reject(new Error('用户ID不存在'))
+ return
+ }
+
// 如果 TIM 实例不存在,等待初始化
if (!this.tim) {
console.log('TIM实例不存在,等待初始化...')
@@ -1071,12 +1078,13 @@ class TimChatManager {
if (timeoutHandle) clearTimeout(timeoutHandle)
this.getGroupListInternal().then(resolve).catch(reject)
} else if (waitTime >= maxWaitTime) {
- console.error('等待SDK就绪超时')
+ console.error('等待SDK就绪超时,当前isLoggedIn:', this.isLoggedIn)
if (timeoutHandle) clearTimeout(timeoutHandle)
+ // 超时时返回错误而不是继续等待
reject(new Error('SDK初始化超时,请检查网络连接'))
} else {
waitTime += checkInterval
- console.log(`等待SDK就绪... (${Math.floor(waitTime / 1000)}/${Math.floor(maxWaitTime / 1000)}秒)`)
+ console.log(`等待SDK就绪... (${Math.floor(waitTime / 1000)}/${Math.floor(maxWaitTime / 1000)}秒, isLoggedIn: ${this.isLoggedIn})`)
timeoutHandle = setTimeout(checkSDKReady, checkInterval)
}
}
@@ -2753,6 +2761,7 @@ class TimChatManager {
// 标记会话为已读
markConversationAsRead(conversationID) {
+
if (!this.tim || !this.isLoggedIn) {
console.log('⚠️ TIM未初始化或未登录,无法标记会话已读');
return;
@@ -2772,6 +2781,7 @@ class TimChatManager {
}
}
+
// 更新会话列表
updateConversationListOnNewMessage(message) {
try {