Compare commits

...

5 Commits

8 changed files with 291 additions and 189 deletions

View File

@ -376,11 +376,20 @@ function eventTypeLabel(eventType) {
}
function resolveUserName(userId) {
const id = String(userId || "");
if (!id) return "";
const map = userNameMap.value || {};
return String(map[id] || "") || id;
}
function refreshChatRoom() {
if (!props.fromChat) return;
const pending = uni.getStorageSync(PENDING_FOLLOWUP_SEND_STORAGE_KEY);
if (pending && typeof pending === "object") {
chatGroupId.value = String(pending.chatGroupId || pending.groupId || "");
}
}
function formatTodo(todo) {
const status = getStatus(todo);
const plannedExecutionTime = todo?.plannedExecutionTime;
@ -446,13 +455,23 @@ async function getMore() {
toast(res?.message || "获取回访任务失败");
return;
}
const arr = Array.isArray(res.data) ? res.data : [];
// { success, data: { data: [], total } }
const payload = res?.data;
const arr = payload && Array.isArray(payload.data)
? payload.data
: Array.isArray(payload)
? payload
: [];
const next = arr.map(formatTodo);
total.value = typeof res.total === "number" ? res.total : 0;
total.value = payload && typeof payload.total === "number" ? payload.total : 0;
pages.value = Math.ceil(total.value / pageSize) || 0;
list.value = page.value === 1 ? next : [...list.value, ...next];
page.value += 1;
} catch (e) {
console.error("getCustomerTodos failed:", e);
toast("获取回访任务失败");
} finally {
loading.value = false;
}

View File

@ -9,10 +9,15 @@
</view>
</picker>
<uni-datetime-picker type="daterange" :value="dateRange" @change="pickTimeRange">
<uni-datetime-picker type="daterange" v-model="dateRange" @change="pickTimeRange">
<view class="filter-pill">
<view class="pill-text">{{ dateRangeLabel }}</view>
<uni-icons type="arrowdown" size="12" color="#666" />
<view class="pill-icons">
<view v-if="isDateRangeActive" class="pill-clear" @tap.stop="clearTimeRange" @click.stop="clearTimeRange">
<uni-icons type="closeempty" size="16" color="#666" />
</view>
<uni-icons type="arrowdown" size="12" color="#666" />
</view>
</view>
</uni-datetime-picker>
</view>
@ -80,7 +85,7 @@ const props = defineProps({
floatingBottom: { type: Number, default: 16 },
});
const FALLBACK_TEMPLATE_TYPES = ['outpatient', 'inhospital', 'preConsultation', 'physicalExaminationTemplate'];
const FALLBACK_TEMPLATE_TYPES = ['outpatient', 'inhospital', 'preConsultationRecord', 'physicalExaminationTemplate'];
const templates = ref([]);
const selectableTemplates = computed(() => templates.value.filter((i) => i && i.templateType && typeof i.name === 'string' && i.name.trim()));
const useActionSheet = computed(() => selectableTemplates.value.length > 0 && selectableTemplates.value.length <= 6);
@ -97,6 +102,9 @@ const currentType = ref({ name: '全部', value: 'ALL' });
const records = ref([]);
const dateRange = ref([]);
const isDateRangeActive = computed(
() => Array.isArray(dateRange.value) && dateRange.value.length === 2 && dateRange.value[0] && dateRange.value[1]
);
const dateRangeLabel = computed(() => {
if (Array.isArray(dateRange.value) && dateRange.value.length === 2 && dateRange.value[0] && dateRange.value[1]) {
return `${dateRange.value[0]}${dateRange.value[1]}`;
@ -226,12 +234,13 @@ async function loadTeamMembers() {
function getSortTimeTitle(templateType) {
const rawType = String(templateType || '');
const ui = normalizeMedicalType(rawType);
// 使 timeTitle
if (ui === 'preConsultationRecord') return 'consultationDate';
const t = templateMap.value[rawType] || {};
if (t?.service?.timeTitle) return String(t.service.timeTitle);
const ui = normalizeMedicalType(rawType);
if (ui === 'outpatient') return 'visitTime';
if (ui === 'inhospital') return 'inhosDate';
if (ui === 'preConsultation') return 'consultDate';
if (ui === 'physicalExaminationTemplate') return 'inspectDate';
return '';
}
@ -275,14 +284,15 @@ function normalizeMedicalType(raw) {
const s = String(raw || '').trim();
if (!s) return '';
const lower = s.toLowerCase();
if (lower.includes('preconsult') || (lower.includes('pre') && lower.includes('consult'))) return 'preConsultation';
if (lower.includes('preconsult') || (lower.includes('pre') && lower.includes('consult'))) return 'preConsultationRecord';
if (lower === 'outpatient' || lower === 'out_patient' || lower === 'out-patient') return 'outpatient';
if (lower === 'inhospital' || lower === 'in_hospital' || lower === 'in-hospital' || lower === 'inpatient') return 'inhospital';
if (lower === 'preconsultation' || lower === 'pre_consultation' || lower === 'pre-consultation') return 'preConsultation';
if (lower === 'preconsultation' || lower === 'pre_consultation' || lower === 'pre-consultation') return 'preConsultationRecord';
if (lower === 'physicalexaminationtemplate' || lower === 'physicalexamination' || lower === 'physical_examination') return 'physicalExaminationTemplate';
if (s === 'outPatient') return 'outpatient';
if (s === 'inHospital') return 'inhospital';
if (s === 'preConsultation') return 'preConsultation';
if (s === 'preConsultation') return 'preConsultationRecord';
if (s === 'preConsultationRecord') return 'preConsultationRecord';
if (s === 'physicalExaminationTemplate') return 'physicalExaminationTemplate';
return s;
}
@ -389,7 +399,7 @@ async function refreshList() {
const tagClass = {
outpatient: 'bg-amber',
inhospital: 'bg-teal',
preConsultation: 'bg-indigo',
preConsultationRecord: 'bg-indigo',
physicalExaminationTemplate: 'bg-green',
};
@ -401,14 +411,14 @@ function resolveRecordType(r) {
if (r.inspectDate || r.positiveFind || r.inspectSummary) return 'physicalExaminationTemplate';
if (r.inhosDate || r.surgeryName || r.surgeryDate || r.operationDate) return 'inhospital';
if (r.visitTime || r.disposePlan || r.treatmentPlan) return 'outpatient';
if (r.consultDate || r.presentIllness || r.presentIllnessHistory || r.pastHistory) return 'preConsultation';
if (r.consultationDate || r.consultDate || r.presentIllness || r.presentIllnessHistory || r.pastHistory) return 'preConsultationRecord';
return '';
}
function getDiagnosis(r) {
if (!r) return '--';
const t = resolveRecordType(r);
if (t === 'preConsultation') return normalizeText(r.chiefComplaint) || normalizeText(r.summary) || '--';
if (t === 'preConsultationRecord') return normalizeText(r.chiefComplaint) || normalizeText(r.summary) || '--';
if (t === 'physicalExaminationTemplate') return formatPositiveFind(r.positiveFind) || normalizeText(r.summary) || '--';
if (t === 'outpatient' || t === 'inhospital') return normalizeText(r.diagnosisName || r.diagnosis) || normalizeText(r.summary) || '--';
return normalizeText(r.diagnosisName || r.diagnosis || r.summary) || '--';
@ -433,7 +443,7 @@ function getDisplayLines(r) {
if (t === 'physicalExaminationTemplate') {
return [{ label: '体检小结:', value: firstLine(r.summary || r.inspectSummary) }];
}
if (t === 'preConsultation') {
if (t === 'preConsultationRecord') {
const lines = [
{ label: '主诉:', value: firstLine(r.chiefComplaint) },
{ label: '现病史:', value: firstLine(r.presentIllness || r.presentIllnessHistory) },
@ -461,7 +471,19 @@ function pickType(e) {
refreshList();
}
function pickTimeRange(val) {
dateRange.value = val;
if (Array.isArray(val)) {
dateRange.value = val;
} else if (val && typeof val === 'object' && Array.isArray(val.value)) {
dateRange.value = val.value;
} else if (val && typeof val === 'object' && val.detail && Array.isArray(val.detail.value)) {
dateRange.value = val.detail.value;
} else {
dateRange.value = [];
}
refreshList();
}
function clearTimeRange() {
dateRange.value = [];
refreshList();
}
@ -589,6 +611,17 @@ watch(
text-overflow: ellipsis;
white-space: nowrap;
}
.pill-icons {
display: flex;
align-items: center;
gap: 12rpx;
flex-shrink: 0;
}
.pill-clear {
display: flex;
align-items: center;
justify-content: center;
}
.share-tip {
padding: 20rpx 28rpx 0;

View File

@ -136,7 +136,7 @@ function formatPatient(raw) {
const lr = raw.latestRecord;
const type = normalizeRecordTypeLabel(lr.type || lr.medicalTypeName || lr.medicalType || '');
const date = lr.date || '';
const diagnosis = lr.diagnosis || '';
const diagnosis = normalizeBriefText(lr.diagnosisName || lr.inspectSummary || lr.chiefComplaint || lr.diagnosis || '');
if (type || date || diagnosis) {
record = {
type: type || '-',
@ -169,6 +169,34 @@ function normalizeText(value) {
return String(value || '').trim();
}
function normalizeBriefText(value) {
if (value === null || value === undefined) return '';
if (Array.isArray(value)) {
const parts = value.map((i) => normalizeBriefText(i)).filter((i) => String(i).trim());
return parts.join('');
}
let s = String(value || '').trim();
if (!s) return '';
// "[]" JSON
if (s === '[]' || s === '[ ]') return '';
if (s.startsWith('[') && s.endsWith(']')) {
try {
const parsed = JSON.parse(s);
if (Array.isArray(parsed)) {
s = parsed.map((i) => normalizeBriefText(i)).filter((i) => String(i).trim()).join('');
}
} catch {
// JSON []
s = s.replace(/^\[\s*/, '').replace(/\s*\]$/, '');
}
}
s = String(s || '').replace(/[\r\n]+/g, ' ').replace(/\s+/g, ' ').trim();
if (s === '[]' || s === '[ ]') return '';
return s;
}
function normalizeDigits(value) {
const s = normalizeText(value);
return s.replace(/\D/g, '');

View File

@ -24,6 +24,10 @@ const ALIAS_MAP = {
presentIllnessHistory: 'presentIllness',
pastMedicalHistory: 'pastHistory',
},
preConsultationRecord: {
presentIllnessHistory: 'presentIllness',
pastMedicalHistory: 'pastHistory',
},
};
export function normalizeVisitRecordFormData(templateType, raw) {
@ -37,4 +41,3 @@ export function normalizeVisitRecordFormData(templateType, raw) {
return out;
}

View File

@ -76,6 +76,7 @@ const forms = computed(() => ({ ...detail.value, ...form }));
const HIDDEN_FIELD_NAMES = {
outpatient: ['就诊机构', '就诊科室', '机构名称', '责任医生'],
inhospital: ['就诊机构', '机构名称'],
physicalExaminationTemplate: ['体检套餐名称'],
};
const HIDDEN_FIELD_TITLES = {
// systemFieldName/title
@ -87,6 +88,8 @@ const HIDDEN_FIELD_TITLES = {
// - : corp
// - : corpName
inhospital: ['corp', 'corpName'],
// - : inspectPakageName
physicalExaminationTemplate: ['inspectPakageName'],
};
function shouldHideField(item) {
const t = String(templateType.value || '');
@ -306,10 +309,13 @@ async function remove() {
height: 100vh;
display: flex;
flex-direction: column;
position: relative;
}
.scroll {
flex: 1;
min-height: 0;
position: relative;
z-index: 1;
}
.scroll-gap {
height: calc(240rpx + env(safe-area-inset-bottom));
@ -340,6 +346,7 @@ async function remove() {
display: flex;
gap: 24rpx;
box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
z-index: 50;
}
.btn {
flex: 1;

View File

@ -49,8 +49,8 @@
</template>
<script setup>
import { computed, ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import dayjs from 'dayjs';
import api from '@/utils/api';
import { loading, hideLoading, toast } from '@/utils/widget';
@ -65,6 +65,8 @@ const medicalType = ref('');
const rawType = ref('');
const record = ref({});
const temp = ref(null);
const needReload = ref(false);
let recordChangedHandler = null;
const files = computed(() => {
const arr = record.value?.files;
@ -79,14 +81,16 @@ function normalizeMedicalType(raw) {
const s = String(raw || '').trim();
if (!s) return '';
const lower = s.toLowerCase();
if (lower.includes('preconsult') || (lower.includes('pre') && lower.includes('consult'))) return 'preConsultation';
if (lower.includes('preconsultationrecord')) return 'preConsultationRecord';
if (lower.includes('preconsult') || (lower.includes('pre') && lower.includes('consult'))) return 'preConsultationRecord';
if (lower === 'outpatient' || lower === 'out_patient' || lower === 'out-patient') return 'outpatient';
if (lower === 'inhospital' || lower === 'in_hospital' || lower === 'in-hospital' || lower === 'inpatient') return 'inhospital';
if (lower === 'preconsultation' || lower === 'pre_consultation' || lower === 'pre-consultation') return 'preConsultation';
if (lower === 'preconsultation' || lower === 'pre_consultation' || lower === 'pre-consultation') return 'preConsultationRecord';
if (lower === 'physicalexaminationtemplate' || lower === 'physicalexamination' || lower === 'physical_examination') return 'physicalExaminationTemplate';
if (s === 'outPatient') return 'outpatient';
if (s === 'inHospital') return 'inhospital';
if (s === 'preConsultation') return 'preConsultation';
if (s === 'preConsultation') return 'preConsultationRecord';
if (s === 'preConsultationRecord') return 'preConsultationRecord';
if (s === 'physicalExaminationTemplate') return 'physicalExaminationTemplate';
return s;
}
@ -98,7 +102,7 @@ const typeLabel = computed(() => record.value?.tempName || temp.value?.name || g
function getDefaultTimeTitle(t) {
if (t === 'outpatient') return 'visitTime';
if (t === 'inhospital') return 'inhosDate';
if (t === 'preConsultation') return 'consultDate';
if (t === 'preConsultationRecord') return 'consultationDate';
if (t === 'physicalExaminationTemplate') return 'inspectDate';
return '';
}
@ -106,7 +110,7 @@ function getDefaultTimeTitle(t) {
function getDefaultTimeName(t) {
if (t === 'outpatient') return '就诊日期';
if (t === 'inhospital') return '入院日期';
if (t === 'preConsultation') return '问诊日期';
if (t === 'preConsultationRecord') return '问诊日期';
if (t === 'physicalExaminationTemplate') return '体检日期';
return '日期';
}
@ -212,7 +216,9 @@ const sections = computed(() => {
? ['corp', 'deptName', 'corpName', 'doctor']
: t === 'inhospital'
? ['corp', 'corpName']
: []);
: t === 'physicalExaminationTemplate'
? ['inspectPakageName']
: []);
const list = [];
const pushedNames = new Set();
@ -289,6 +295,41 @@ const topText = computed(() => {
return suffix ? `${time || '--'} ${suffix}` : `${time || '--'}`;
});
async function fetchRecord({ silent = false } = {}) {
if (!archiveId.value || !id.value || !medicalType.value) return false;
const corpId = getCorpId();
if (!corpId) {
if (!silent) toast('缺少 corpId');
return false;
}
if (!silent) loading('加载中...');
try {
const res = await api('getMedicalRecordById', {
_id: id.value,
corpId,
memberId: archiveId.value,
medicalType: medicalType.value,
});
const r = res?.record || res?.data?.record || null;
if (!res?.success || !r) return false;
const raw = String(r?.templateType || r?.medicalType || medicalType.value || '');
rawType.value = raw;
const ui = normalizeMedicalType(raw);
record.value = normalizeVisitRecordFormData(ui, r);
temp.value = await loadTemplate(raw);
uni.setNavigationBarTitle({ title: String(typeLabel.value || '病历详情') });
return true;
} catch (error) {
console.error('获取病历记录失败:', error);
if (!silent) toast('加载失败');
return false;
} finally {
if (!silent) hideLoading();
}
}
onLoad(async (opt) => {
archiveId.value = opt?.archiveId ? String(opt.archiveId) : '';
id.value = opt?.id ? String(opt.id) : '';
@ -298,45 +339,32 @@ onLoad(async (opt) => {
setTimeout(() => uni.navigateBack(), 300);
return;
}
// 使 API
loading('加载中...');
try {
const corpId = getCorpId();
if (!corpId) {
hideLoading();
toast('缺少 corpId');
setTimeout(() => uni.navigateBack(), 300);
return;
}
const res = await api('getMedicalRecordById', {
_id: id.value,
corpId,
memberId: archiveId.value,
medicalType: medicalType.value,
});
hideLoading();
const r = res?.record || res?.data?.record || null;
if (!res?.success || !r) {
toast('记录不存在');
setTimeout(() => uni.navigateBack(), 300);
return;
}
const raw = String(r?.templateType || r?.medicalType || medicalType.value || '');
rawType.value = raw;
const ui = normalizeMedicalType(raw);
record.value = normalizeVisitRecordFormData(ui, r);
temp.value = await loadTemplate(raw);
uni.setNavigationBarTitle({ title: String(typeLabel.value || '病历详情') });
} catch (error) {
hideLoading();
console.error('获取病历记录失败:', error);
toast('加载失败');
const ok = await fetchRecord();
if (!ok) {
toast('记录不存在');
setTimeout(() => uni.navigateBack(), 300);
}
});
onMounted(() => {
recordChangedHandler = () => {
needReload.value = true;
};
//
uni.$on('archive-detail:visit-record-changed', recordChangedHandler);
});
onUnmounted(() => {
if (recordChangedHandler) uni.$off('archive-detail:visit-record-changed', recordChangedHandler);
recordChangedHandler = null;
});
onShow(async () => {
if (!needReload.value) return;
needReload.value = false;
await fetchRecord({ silent: true });
});
function preview(idx) {
const urls = files.value.map((i) => i.url);
uni.previewImage({ urls, current: urls[idx] });

View File

@ -212,6 +212,7 @@ const lastPatientsLoadOk = ref(true);
const loadedGroupsTeamId = ref('');
let enterRefreshInflight = null;
const hasEnteredOnce = ref(false);
let lastReloadStartedAt = 0;
const accountStore = useAccountStore();
const { account, doctorInfo } = storeToRefs(accountStore);
@ -852,15 +853,16 @@ function normalizeMedicalType(raw) {
//
if (s.includes('门诊')) return 'outpatient';
if (s.includes('住院') || s.includes('入院')) return 'inhospital';
if (s.includes('预问诊') || s.includes('问诊')) return 'preConsultation';
if (s.includes('预问诊') || s.includes('问诊')) return 'preConsultationRecord';
if (s.includes('体检')) return 'physicalExaminationTemplate';
if (lower.includes('preconsult') || (lower.includes('pre') && lower.includes('consult'))) return 'preConsultation';
if (lower.includes('preconsult') || (lower.includes('pre') && lower.includes('consult'))) return 'preConsultationRecord';
if (lower === 'outpatient' || lower === 'out_patient' || lower === 'out-patient') return 'outpatient';
if (lower === 'inhospital' || lower === 'in_hospital' || lower === 'in-hospital' || lower === 'inpatient') return 'inhospital';
if (lower === 'physicalexaminationtemplate' || lower === 'physicalexamination' || lower === 'physical_examination') return 'physicalExaminationTemplate';
if (s === 'outPatient') return 'outpatient';
if (s === 'inHospital') return 'inhospital';
if (s === 'preConsultation') return 'preConsultation';
if (s === 'preConsultation') return 'preConsultationRecord';
if (s === 'preConsultationRecord') return 'preConsultationRecord';
if (s === 'physicalExaminationTemplate') return 'physicalExaminationTemplate';
return s;
}
@ -940,6 +942,7 @@ function resolveLatestRecord(lr) {
'date',
'visitTime',
'inhosDate',
'consultationDate',
'consultDate',
'inspectDate',
'sortTime',
@ -951,77 +954,22 @@ function resolveLatestRecord(lr) {
);
const rawDateStr = String(rawDate ?? '').trim();
const date = (/^\d{10,13}$/.test(rawDateStr) ? (formatAnyDate(rawDateStr, 'YYYY-MM-DD') || rawDateStr) : rawDateStr)
|| formatAnyDate(pick('visitTime', 'inhosDate', 'consultDate', 'inspectDate', 'sortTime', 'createTime', 'updateTime'), 'YYYY-MM-DD')
|| formatAnyDate(pick('visitTime', 'inhosDate', 'consultationDate', 'consultDate', 'inspectDate', 'sortTime', 'createTime', 'updateTime'), 'YYYY-MM-DD')
|| '-';
let third = '';
// diagnosis使
const directDiagnosis = normalizeText(pick('diagnosis', 'diagnosisName'));
if (String(directDiagnosis || '').trim()) {
third = directDiagnosis;
} else if (uiType === 'outpatient' || uiType === 'inhospital') {
third = normalizeText(pick(
'diagnosisName',
'diagnosis',
'diagnosisList',
'diagnosisNames',
'mainDiagnosis',
'admissionDiagnosis',
'inDiagnosis',
'outDiagnosis',
'outPatientDiagnosis',
'inHospitalDiagnosis'
));
} else if (uiType === 'preConsultation') {
third = normalizeText(
pick(
'diagnosis',
'diagnosisName',
'chiefComplaint',
'chiefComplain',
'chiefComplaintText',
'chiefComplaintContent',
'complaint',
'complaintDesc',
'complaintText',
'mainComplaint',
'mainSuit',
'mainSuitText',
'mainSuitContent',
'chief',
'zs',
'zhuSu',
'cc',
'presentIllness',
'historyOfPresentIllness',
'currentIllness'
)
);
// searchCorpCustomerForCaseList
// - chiefComplaint
// - inspectSummary
// - /diagnosisName
if (uiType === 'outpatient' || uiType === 'inhospital') {
third = normalizeText(pick('diagnosisName', 'diagnosis'));
} else if (uiType === 'physicalExaminationTemplate') {
third = normalizeText(
pick(
'diagnosis',
'diagnosisName',
'summary',
'summaryText',
'inspectSummary',
'checkSummary',
'examSummary',
'physicalSummary',
'briefSummary',
'resultSummary',
'conclusion',
'conclusionText',
'inspectConclusion',
'inspectResult',
'finalConclusion',
'finalSummary',
'reportConclusion',
'reportSummary'
)
);
third = normalizeText(pick('inspectSummary', 'summary', 'summaryText', 'inspectConclusion', 'inspectResult'));
} else if (uiType === 'preConsultationRecord') {
third = normalizeText(pick('chiefComplaint', 'chiefComplain', 'chiefComplaintText', 'chiefComplaintContent'));
} else {
third = normalizeText(pick('diagnosis', 'diagnosisName', 'summary', 'chiefComplaint'));
third = normalizeText(pick('diagnosisName', 'diagnosis', 'inspectSummary', 'summary', 'chiefComplaint'));
}
third = String(third || '').replace(/\s+/g, ' ').trim();
if (!third) {
@ -1033,7 +981,7 @@ function resolveLatestRecord(lr) {
const type = typeLabel || (uiType === 'outpatient' ? '门诊记录'
: uiType === 'inhospital' ? '住院记录'
: uiType === 'preConsultation' ? '预问诊记录'
: uiType === 'preConsultationRecord' ? '预问诊记录'
: uiType === 'physicalExaminationTemplate' ? '体检档案'
: '-');
@ -1217,6 +1165,7 @@ async function reload(reset = true, opts = {}) {
query.includeRecentAddTime = true;
}
lastReloadStartedAt = Date.now();
loading.value = true;
let res;
try {
@ -1769,6 +1718,8 @@ onLoad(async () => {
});
onShow(async () => {
const showAt = Date.now();
const wasEnteredOnce = hasEnteredOnce.value;
const need = uni.getStorageSync(NEED_RELOAD_STORAGE_KEY);
if (need) {
uni.removeStorageSync(NEED_RELOAD_STORAGE_KEY);
@ -1781,6 +1732,12 @@ onShow(async () => {
if (needGroups) uni.removeStorageSync(GROUPS_RELOAD_KEY);
await refreshOnEnter();
// inflight
// onShow reload reload
if (wasEnteredOnce && lastReloadStartedAt && lastReloadStartedAt < showAt) {
await reload(true, { silent: true, keepOnFail: true });
}
});
</script>

View File

@ -1,61 +1,81 @@
export default `
隐私政策
欢迎您访问健康柚平台
下称患者用户在健康柚平台使用我们的服务或产品时我们可能会收集您的相关个人信息健康柚深知个人信息对您的重要性并会尽全力保护您的个人信息安全可靠我们致力于维持您对我们的信任恪守以下原则保护您的个人信息权责一致原则目的明确原则选择同意原则最少够用原则确保安全原则主体参与原则公开透明原则等同时健康柚承诺我们将按业界成熟的安全标准采取相应的安全保护措施来保护您的个人信息
为此我们制定本隐私政策适用于我们为患者提供的产品和服务包括但不限于健康柚微信小程序柚助手微信小程序
在使用健康柚平台提供的产品或服务前请您务必认真仔细阅读并确认充分理解本隐私政策在确认充分理解并同意后再开始使用一旦您主动选择确认本隐私政策并继续使用的即视为同意本隐私政策的全部内容如您不同意相关协议或其中的任何条款的您应停止访问健康柚平台或使用健康柚产品和服务
如您是未成年人请您和您的监护人仔细阅读本政策并在征得您的监护人授权同意的前提下使用我们的服务或向我们提供个人信息
欢迎您访问柚助手平台
您在柚助手平台使用我们的服务或产品时我们可能会收集您的相关个人信息我们深知个人信息对您的重要性我们将按照法律法规的规定并参照行业最佳实践保护您的个人信息及隐私安全我们制定本隐私政策并特别提示希望您在使用柚助手平台及相关服务前仔细阅读并理解本隐私政策以便做出适当的选择
本隐私政策将帮助您了解
我们会遵循隐私政策收集使用您的信息但不会仅因您同意本隐私政策而采用强制捆绑的方式一揽子收集个人信息
当您使用或开启相关功能或使用服务时为实现功能服务所必需我们会收集使用相关信息除非是为实现基本业务功能或根据法律法规要求所必需的必要信息您均可以拒绝提供且不影响其他功能或服务我们将在隐私政策中逐项说明哪些是必要信息
如果您未登录帐号我们会通过设备对应的标识符信息来保障信息推送的基本功能如果您登录了帐号我们会根据帐号信息实现信息推送
精确地理位置摄像头麦克风相册存储权限均不会默认开启只有经过您的明示授权才会在为实现特定功能或服务时使用您也可以撤回授权特别需要指出的是即使经过您的授权我们获得了这些敏感权限也不会在相关功能或服务不需要时而收集您的信息
下文将帮您详细了解我们如何收集使用存储传输共享转移如适用与保护个人信息帮您了解查询访问删除更正复制转移个人信息撤回授权和要求我们解释对个人信息处理规则的方式本政策与您使用我们的服务关系密切我们建议您仔细阅读并理解本政策全部内容作出您认为适当的选择有关您个人信息权益的条款重要内容我们已用加粗形式提示请特别关注本隐私政策适用的功能并不面向未成年人开放如您是未成年人请务必不要使用柚助手平台本功能
本隐私政策将帮助您了解以下内容
1我们如何收集和使用您的个人信息
2我们如何使用Cookie和同类技术
3我们如何共享转移公开披露您的个人信息
4我们如何保存和保护您的个人信息
5您的权利
6我们如何处理未成年人的个人信息
7您的个人信息如何在全球范围转移
8本隐私政策更新及通知
9如何联系我们
10争议解决
我们如何收集和使用您的个人信息
个人信息是指以电子或其他方式记录的与已识别或者可识别的自然人有关的各种信息不包括匿名化处理后的信息
我们仅会出于本政策所述的以下目的收集和使用您的个人信息当我们要将信息用于本政策未载明的其他用途时会事先征求您的同意
.我们如何收集和使用个人信息
.我们如何使用cookie和同类技术
.我们如何共享转移公开披露您的个人信息
.我们如何保护您的个人信息
. 管理您的个人信息
. 我们如何处理未成年人的个人信息
. 您的个人信息如何在全球范围转移
. 本政策更新及通知
.如何联系我们
.争议解决
我们如何收集和使用个人信息
我们会按照如下方式收集您在使用服务时主动提供的以及通过自动化手段收集您在使用功能或接受服务过程中产生的信息
() 注册成为用户
健康柚平台提供的服务或产品是基于注册用户使用的如您希望使用健康柚平台提供的服务或产品则需要通过以下步骤完成账号注册
创建健康柚账户我们将提供手机号码授权登陆方式您需要提供您的手机号码如不提供上述注册信息您无法使用需注册成为健康柚平台用户方可使用的服务
() 成员档案管理服务
用户在使用成员档案管理服务时需先添加成员信息包括您的姓名性别年龄与成员关系本人/子女/父母/其他等目的是协助医生对患者进行管理
() 我的服务团队服务
用户在成员档案管理中添加成员信息后使用团队服务时我们可能会收集在健康柚其他平台已与患者建立关系的服务团队信息目的是与服务团队建立联系以确保成员聊天咨询的连续性和准确性我们还可能收集您的登记信息姓名身份证号码性别年龄检查检验报告用药记录过敏史等个人健康生理信息以及与个人身体健康状况相关的身高体重信息用于了解您的健康状况和咨询需求如不收集这类信息我们将无法为您提供健康咨询相关的服务但不影响您使用其他服务
您与团队建立服务关系后您理解并同意将添加的个人信息病历信息就诊记录将向该团队展示
() 回访服务
在您的服务团队人员对您进行回访的过程中我们可能收集您与团队人员的沟通聊天记录为您制定的回访计划向您发送的文章以及您填写的问卷信息以支持您在健康柚平台上获得持续可追溯的回访服务
() 客户服务
当您向我们提出问题投诉或建议时我们需要收集您的通信/通话记录您提供的联系方式信息您为了证明相关事实提供的信息以及您参与问卷调查时向我们发送的问卷答复信息我们收集上述信息的法律依据是基于向您提供健康柚平台服务所必需为您解决您在使用平台及享受服务过程中所遇到的问题以及向您提供相关问题的处理方案和结果如不收集这类信息您的投诉建议和反馈将无法得到及时有效处理但不影响您使用其它服务
() 保障功能运行和风控服务
为保障您正常使用我们及我们关联公司合作伙伴提供的服务维护我们系统基础功能的正常运行拦截钓鱼网站欺诈防止网络漏洞计算机病毒网络攻击网络侵入改进及优化我们的服务体验以及保障您的账号安全我们需要整合我们已根据本隐私政策合法收集的您的个人基本信息姓名身份证号码手机号码性别年龄个人生理健康信息既往病史用药记录体重并收集使用或整合您的网络身份标识信息BSSIDDNS地址IP地址SSID代理信息网络类型网络名称掩码信息个人常用设备信息IMEIIMSI设备IDMAC地址IDFAIDFVAndroidIdMCCMNCUUID标准国家码操作系统信息Cookie启用状态重力传感陀螺仪传感加速度传感已安装应用列表位置信息经纬度人脸识别信息以及我们关联公司合作伙伴取得您授权或依据法律共享的信息我们收集上述信息的法律依据是基于法定义务及向您提供健康柚平台服务所必需以综合判断您账户及交易风险进行身份验证检测及防范账户安全事件并依法采取必要的记录审计分析处置措施如不收集这类信息您将无法使用健康柚平台及健康柚平台提供的相应服务
() 我们如何使用您的信息
1我们会对我们提供的服务使用情况进行统计并可能会与公众或第三方共享这些统计信息以用于产品开发服务优化安全保障数据分析等目的但这些统计信息不包含您的任何身份识别信息
2根据相关法律法规规定以下情形中收集使用您的个人信息无需征得您的授权同意
1为订立履行您作为一方当事人的合同所必需
2为履行法定职责或者法定义务所必需
3为应对突发公共卫生事件或者紧急情况下为保护自然人的生命健康和财产安全所必需
4为公共利益实施新闻报道舆论监督等行为在合理的范围内处理您的个人信息
5依照法律规定在合理的范围内处理您自行公开或者其他已经合法公开的个人信息
6法律行政法规规定的其他情形
我们如何使用Cookies和同类技术
() Cookies
柚助手平台提供的服务或产品是基于注册用户使用的如您希望使用柚助手平台提供的服务或产品则需要通过以下步骤完成账号注册
创建柚助手账户我们将提供手机号码授权登陆方式您需要提供您的手机号码如不提供上述注册信息您无法使用需注册成为柚助手平台用户方可使用的服务
2. 柚助手平台大多数服务是面向医疗卫生专业人士提供注册成功后为保障您专业人士身份的真实性从而保障内容的专业性/活动资格的真实性平台有义务验证您的医疗卫生专业人士的身份因此您需要完善您的身份信息我们可能需要收集您以下相关信息您需要提供姓名医院名称科室岗位职称个人介绍情况以及证件证明资料如医师执业资格证照片页或医师执业资格证信息页进行实名实人认证及资质审核
如果您不提供这些信息可能会影响您在柚助手平台部分核心业务功能的正常使用如在线咨询等但不会影响您进行基本的浏览搜索
3. 如您拒绝提供手机号码进行身份验证将导致注册不成功您可以退出注册页面后进入柚助手平台仅浏览平台内的相关信息内容但不可进行任何其它的具体操作或使用平台提供的核心服务等
4.您提供的上述信息将在您使用本服务期间持续授权我们使用在您注销账号时我们将停止使用并删除上述信息
6.您在使用我们提供的搜索推送统计等服务时我们会收集您搜索的关键字信息搜索历史记录个人信息BSSIDIMSISNSSIDICCIDSUPISUCI传感器列表软件安装列表位置联系人通话记录日历短信本机电话号码图片音视频设备信息包括您使用的设备属性连接和状态信息例如设备型号设备标识符如IMEI/AndroidID/IDFA/OPENUDID/GUID/OAID设备MAC地址电信运营商等软硬件特征信息为了提供高效的搜索服务部分信息会暂时存储在您的本地设备中
向您提供的产品和服务
1.在线沟通及回访服务
当您通过柚助手小程序对患者进行沟通或随访时我们可能会收集您与患者的沟通聊天记录为患者制定的回访计划向患者发送的宣教文章和问卷信息以便于支持您完成患者持续的可追溯的随访
您知晓并同意您的真实姓名主要执业点医院名称及科室职称以及您补充的个人主页上的信息如您的真实头像性别擅长疾病及个人简介会在患者沟通及随访服务过程中展现同时出于患教以及帮助其他患者的目的您与患者的交流信息将有可能作为优质内容在对患者进行匿名化和/或去标识化处理后公开展示您的真实姓名真实头像如有职称主要执业点医院以及科室也将一并展示
2.运营与安全保障
1运营与安全
我们致力于为您提供安全可信的产品与使用环境提供优质高效可靠的服务与信息是我们的核心目标
2设备信息与日志信息
a.为了保障软件服务的安全运营的质量及效率我们会收集您的硬件型号操作系统版本号国际移动设备识别码唯一设备标识符网络设备硬件地址IP地址WLAN接入点蓝牙基站软件版本号网络接入方式类型状态网络质量数据操作使用服务日志
b.为了预防恶意程序确保运营质量及效率我们会收集安装的应用信息或正在运行的进程信息应用程序的总体运行使用情况与频率应用崩溃情况总体安装使用情况性能数据应用来源
c.我们可能使用您的账户信息设备信息服务日志信息以及我们关联公司合作方在获得您授权或依法可以共享的信息用于判断账户安全进行身份验证检测及防范安全事件
我们获取的设备权限
为向您提供便捷优质的服务我们可能会调用您设备上的一些权限在您使用相应功能时会看到弹窗提醒询问您是否授权
请您注意上述附加功能可能需要您在您的设备中向我们开启您的相机摄像头相册图片库麦克风系统通知的访问权限以实现这些功能所涉及的信息的收集和使用我们在您首次使用该类附加功能需开启相应权限时弹窗对您进行提示您选择开启相应权限则可进一步使用相应服务
请您注意您开启这些权限即代表您授权我们可以收集和使用这些个人信息来实现上述的功能您关闭权限即代表您取消了这些授权则我们将不再继续收集和使用您的这些个人信息也无法为您提供上述与这些授权所对应的功能您关闭权限的决定不会影响此前基于您的授权所进行的个人信息的处理
3我们收集的个人信息
当您通过网站客户端小程序等服务入口使用我们的服务时我们可能从您的设备处收集您的IP地址设备型号唯一设备识别码浏览器型号粗略位置信息例如国家或者城市信息安装的应用信息以及其他的设备技术信息
收集该等信息主要为了保障服务的安全运行我们同时也需要留存相应的日志来记录我们网站移动客户端等服务入口的运行状态以符合法律法规的规定
4收集使用个人信息目的变更
请您了解随着我们业务的发展可能会对柚助手平台的功能和提供的服务有所调整变化原则上当新功能或服务与我们当前提供的功能或服务相关时收集与使用的个人信息将与原处理目的具有直接或合理关联在与原处理目的无直接或合理关联的场景下我们收集使用您的个人信息会再次进行告知并征得您的同意
5依法豁免征得同意收集和使用的个人信息
请您理解在下列情形中根据法律法规及相关国家标准我们收集和使用您的个人信息无需征得您的授权同意
a) 为订立履行您作为一方当事人的合同所必需
b) 为履行法定职责或者法定义务所必需
c) 为应对突发公共卫生事件或者紧急情况下为保护自然人的生命健康和财产安全所必需
d) 为公共利益实施新闻报道舆论监督等行为在合理的范围内处理您的个人信息
e) 依照法律规定在合理的范围内处理您自行公开或者其他已经合法公开的个人信息
f) 法律行政法规规定的其他情形
6敏感个人信息
我们收集和使用您的敏感个人信息的将以弹窗等形式取得您的单独同意您理解并且同意您的个人敏感信息可按本政策所述的目的和方式进行处理我们会在得到您的同意后收集和使用您的敏感信息以实现与平台在线业务相关的功能并允许您对这些敏感信息的收集与使用做出不同意的选择但是拒绝使用这些信息会影响您使用相关功能
如我们停止运营柚助手产品或服务我们将及时停止继续收集您个人信息将停止运营的通知以逐一送达或公告的形式通知您并对我们所持有的与已关停业务相关的个人信息进行删除或匿名化处理涉及未满14周岁的未成年人个人信息的我们会并将停止运营的通知及时告知未成年人监护人
7当我们要将信息用于本政策未载明的其他用途时会事先征求您的同意当我们要将基于特定目的收集而来的信息用于其他目的是会事先征求您的同意请您知悉我们向您提供的产品与/或服务将不断更新变化如果您选择使用本隐私政策中尚未列明的其他产品与/或服务时我们会在收集您的个人信息前通过协议页面提示等方式向您详细说明信息收集的目的方式范围并征求您的同意若您不同意提供前述信息您可能无法使用该项产品与/或服务但不影响您使用现有产品与/或服务
我们如何使用Cookie和同类技术
为确保网站正常运转为您获得更轻松的访问体验我们会在您的计算机或移动设备上存储名为Cookies的小数据文件Cookies通常包含标识符站点名称以及一些号码和字符借助于Cookies网站能够记住您的选择存储您的偏好等数据
我们不会将Cookies用于本政策所述目的之外的任何用途您可根据自己的偏好管理或删除Cookies您可以清除计算机或手机上保存的所有Cookies大部分网络浏览器都设有阻止Cookies的功能如果您这么做则需要在每一次访问我们的网站时亲自更改用户设置
第三方合作伙伴通过Cookies收集和使用您的信息不受本政策约束而是受到其自身的信息保护声明约束我们不对第三方的Cookies或同类技术承担责任
我们如何共享转移公开披露您的个人信息
() 对外提供
如您主动自愿要求我们向第三方提供您的个人信息的我们将基于您同意的目的在相应页面中以适当方式告知您个人信息接收方的名称和联系方式例如您主动要求使用健康柚平台账户登录第三方产品或服务的我们或第三方将在关联登录页面告知您为此目的健康柚平台需向第三方提供的个人信息以及第三方的名称和联系方式
共享
如您主动自愿要求我们向第三方提供您的个人信息的我们将基于您同意的目的在相应页面中以适当方式告知您个人信息接收方的名称和联系方式例如您主动要求使用助手平台账户登录第三方产品或服务的我们或第三方将在关联登录页面告知您为此目的助手平台需向第三方提供的个人信息以及第三方的名称和联系方式
我们基于以下情况可能会对外共享您的个人信息
1在法定情形下的共享我们可能会根据法律法规规定或按政府主管部门的强制性要求对外共享您的个人信息我们为履行法定义务而向第三方提供您的个人信息的我们将在相应页面中以适当方式告知您个人信息接收方的名称和联系信息
2与关联公司间共享我们只会共享必要的个人信息如为便于您通过统一账号使用我们关联公司产品或服务我们会向关联公司共享您必要的账户信息如果我们共享您的个人敏感信息或关联公司改变个人信息的使用及处理目的将在此就分享目的范围形式等必要内容征求您的授权统一
3基于向您提供健康柚平台服务所必需部分服务可能是我们的关联公司和合作机构授权合作伙伴或我们与第三方共同向您提供因此为向您提供健康柚平台服务我们必需将您的个人信息提供给我们的关联公司及业务合作伙伴例如在某些情况下我们必须与物流服务提供商共享您的收货信息才能安排配送我们仅会出于合法正当必要特定明确的目的共享您的个人信息并且只会共享提供服务所必要的个人信息我们的合作伙伴无权将共享的个人信息用于任何其他用途
3基于向您提供助手平台服务所必需部分服务可能是我们的关联公司和合作机构授权合作伙伴或我们与第三方共同向您提供因此为向您提供助手平台服务我们必需将您的个人信息提供给我们的关联公司及业务合作伙伴例如在某些情况下我们必须与物流服务提供商共享您的收货信息才能安排配送我们仅会出于合法正当必要特定明确的目的共享您的个人信息并且只会共享提供服务所必要的个人信息我们的合作伙伴无权将共享的个人信息用于任何其他用途
目前我们的授权合作伙伴包含以下类型
1)技术服务供应商我们可能会将您的个人信息共享给支持我们功能的第三方这些支持包括为我们提供基础设施技术服务安全保障服务代表我们发出短信的通讯服务供应商物流配送服务数据处理等我们共享这些信息的目的是可以实现我们产品或服务的功能比如我们必须与物流服务提供商共享您的收货信息才能安排送货
2)分析服务类的授权合作伙伴在征得您的许可后我们可能将不能识别您的个人身份信息的统计或匿名信息共享给提供分析服务的合作伙伴对于分析数据的伙伴我们仅会向这些合作伙伴提供不能识别个人身份的统计或匿名信息
@ -79,6 +99,7 @@ export default `
4依照本法规定在合理的范围内处理个人自行公开或者其他已经合法公开的个人信息
5法律行政法规规定的其他情形
6已经匿名化处理的您的个人信息指经过处理无法识别特定自然人且不能复原
我们如何保存和保护您的个人信息
() 个人信息的保存
1保存期限如您删除或通过系统设置拒绝我们对您的个人信息进行收集或者在您申请注销账号经核实身份注销后我们将停止使用并删除或匿名化处理您的个人信息我们的个人信息保存期限为实现目的所需及法律法规要求的最短时间但法律法规另有规定或者您另行授权同意的除外
@ -92,26 +113,27 @@ export default `
2安全提醒
1)互联网并非绝对安全的环境我们强烈建议您不要通过电子邮件即使通讯及与其他用户交流等未加密的方式发送个人信息请登陆时使用手机验证码协助我们保证您的账号安全
2)请使用复杂密码协助我们保证您的账号安全我们将尽力保障您发送给我们的任何信息的安全性如果我们的物理技术或管理防护设施遭到破坏导致信息被非授权访问公开披露篡改或毁坏导致您的合法权益受损我们将承担相应的法律责任
3)您在使用健康柚平台及服务时请谨慎发表上传可能会涉及您或他人隐私的信息也勿将该等信息通过健康柚平台的服务传播给他人若因您该等行为引起您或他人的隐私泄露由您自行承担责任
4)请勿在使用健康柚平台服务时公开透露自己的各类财产账户银行卡信用卡第三方支付账户及对应密码等重要资料否则由此带来的损失由您自行承担责任
5)健康柚平台一旦发现假冒仿冒盗用他人名义进行平台认证的健康柚有权立即删除用户信息并有权在用户提供充分证据前禁止其使用平台服务
3)您在使用助手平台及服务时请谨慎发表上传可能会涉及您或他人隐私的信息也勿将该等信息通过助手平台的服务传播给他人若因您该等行为引起您或他人的隐私泄露由您自行承担责任
4)请勿在使用助手平台服务时公开透露自己的各类财产账户银行卡信用卡第三方支付账户及对应密码等重要资料否则由此带来的损失由您自行承担责任
5)助手平台一旦发现假冒仿冒盗用他人名义进行平台认证的助手有权立即删除用户信息并有权在用户提供充分证据前禁止其使用平台服务
3安全事件通知
1)我们会制定相应的网络安全事件应急预案及时处置系统漏洞计算机病毒网络攻击网络侵入等安全风险在发生危害网络安全的事件时我们会立即启动应急预案采取相应的补救措施
2)在不幸发生个人信息安全事件后我们将按照法律法规的要求及时向您告知安全事件的基本情况和可能的影响我们已采取或将要采取的处置措施您可自主防范和降低风险的建议对您的补救措施等我们将及时将事件相关情况以邮件信函电话推送通知等方式告知您难以逐一告知个人信息主体时我们会采取合理有效的方式发布公告
同时我们还将按照监督部门要求主动上报个人信息安全事件的处置情况
请您理解根据法律法规的规定如果我们采取的措施能够有效避免信息泄露篡改丢失造成危害的除非监管部门要求向您通知我们可以选择不向您通知该个人信息安全事件
3)如您发现自己的个人信息泄密尤其是您的账户及密码发生泄露请您立即通过健康柚平台或本隐私政策提供的联系方式联络我们以便我们采取相应措施
您的权利
3) 如您发现自己的个人信息泄密尤其是您的账户及密码发生泄露请您立即通过柚助手平台或本隐私政策提供的联系方式联络我们以便我们采取相应措施
管理您的个人信息
按照中国相关的法律法规标准以及其他国家地区的通行做法我们保障您对自己的个人信息行使以下权利
() 访问您的个人信息
您有权访问您的个人信息法律法规规定的例外情况除外如果您想行使数据访问权可以通过以下方式自行访问
档案信息小程序中您可以通过档案管理中新增查阅删除您的档案信息
咨询记录小程序中您可以通过咨询列表查阅历史咨询记录
问卷信息小程序中您可以通过我的问卷查阅历史填写的问卷记录
个人信息小程序中您可以通过工作台中点击个人头像查看编辑删除个人信息
咨询记录小程序中您可以通过消息列表查阅历史咨询记录
病历记录小程序中您可以通过病历查阅您团队在管的患者病历信息
() 更正您的个人信息
当您发现我们处理的关于您的个人信息有错误时您有权通过客服提出更正申请
() 删除您的个人信息
如果您决定不再使用我们平台需要注销账户请联系客服进入个人中心扫描客户二维码
如果您决定不再使用我们平台需要注销账户请联系客服进入工作台-更多-联系客服
() 改变您授权同意的范围
您可以通过解除绑定删除信息关闭设备功能修改个人设置联系客服等方式改变您授权我们继续收集个人信息的范围或随时撤回您的授权包括对第三方共享信息授权
() 注销帐号
@ -133,15 +155,18 @@ export default `
6响应您的请求将导致您或其他个人组织的合法权益受到严重损害的
7涉及商业秘密的
() 获得解释的权利
您有权要求我们就个人信息处理规则作出解释说明您可以通过第九部分中的联系方式与我们取得联系
您有权要求我们就个人信息处理规则作出解释说明您可以通过微信小程序进入工作台-更多-联系客服与我们取得联系
我们如何处理未成年人的个人信息
6.1如果没有父母或其他监护人的统一儿童不得创建自己的用户账户如您为儿童的我们要求您请您的父母或其他监护人仔细阅读本政策并在征得您的父母或其他监护人同意的前提下使用我们的服务或产品或向我们提供信息
6.2对于经父母或其他监护人同意使用我们的服务或产品而收集儿童个人信息的情况我们只会在法律法规允许父母或其他监护人明确同意或者保护儿童所必要的情况下使用共享转让或披露此信息
您的个人信息如何在全球范围转移
我们在中华人民共和国境内运营中收集和产生的个人信息储存在中国境内一下情形除外
1. 法律法规有明确规定
2. 获得您的明确授权且经过国家安全相关审查的
针对以上情形我们会确保依据本政策对您的个人信息提供足够的保护
本隐私政策更新及通知
我们的隐私政策可能变更
未经您明确同意我们不会削减您按照本隐私政策所应享有的权利我们会在本页面上发布对本政策所做的任何变更并取得您的同意
@ -154,13 +179,15 @@ export default `
5我们负责处理个人信息安全的责任部门联络方式及投诉渠道发生变化
6个人信息安全影响评估报告表明存在高风险时
我们还会将本政策的旧版本存档供您查阅
如何联系我们
如您对本政策内容有任何疑问意见或建议或发现个人信息可能被泄露的您可以通过以下方式与我们联系一般情况下我们将在15个工作日内回复您的请求可以通过我的-联系客服联系我们或邮寄至下列地址
如您对本政策内容有任何疑问意见或建议或发现个人信息可能被泄露的您可以通过以下方式与我们联系一般情况下我们将在15个工作日内回复您的请求可以通过工作台-更多-联系客服联系我们或邮寄至下列地址
公司名称杭州柚康科技有限公司
法定代表人王荣波
联系地址中国浙江省杭州西湖区塘苗路1号2号楼4楼
争议解决
因本政策以及我们处理您个人信息事宜引起的任何争议您可随时联系我公司个人信息保护相关负责人要求给出回复如果您对我们的回复不满意的认为我们的个人信息处理行为严重损害了您的合法权益的您还可以通过向本隐私政策服务提供商健康柚所在地杭州市有管辖权的人民法院提起诉讼来寻求解决方案
感谢您对健康柚平台以及健康柚产品和服务的信任和使用
因本政策以及我们处理您个人信息事宜引起的任何争议您可随时联系我公司个人信息保护相关负责人要求给出回复如果您对我们的回复不满意的认为我们的个人信息处理行为严重损害了您的合法权益的您还可以通过向本隐私政策服务提供商助手所在地杭州市有管辖权的人民法院提起诉讼来寻求解决方案
感谢您对助手平台以及柚助手产品和服务的信任和使用
`