feat(assistant): unify confirmed memory capture
This commit is contained in:
@@ -1,24 +1,16 @@
|
||||
<template>
|
||||
<view class="memory-card" :class="{ compact }">
|
||||
<template v-if="candidate.status === 'NEEDS_INPUT'">
|
||||
<view class="memory-head">
|
||||
<text class="memory-title">还需要补充信息</text>
|
||||
<text class="memory-tag muted">暂不保存</text>
|
||||
</view>
|
||||
<text class="needs-input-copy">{{ missingPrompt }}</text>
|
||||
</template>
|
||||
|
||||
<template v-else-if="completed">
|
||||
<template v-if="completed">
|
||||
<view class="memory-head">
|
||||
<text class="memory-title">已确认保存</text>
|
||||
<text class="memory-tag success">{{ targetLabel }}</text>
|
||||
</view>
|
||||
<text class="saved-copy">这条事项已保存,后续工作助手可按权限查询。</text>
|
||||
<text class="saved-copy">{{ completedCopy }}</text>
|
||||
</template>
|
||||
|
||||
<template v-else-if="candidate.status === 'DRAFT'">
|
||||
<template v-else-if="candidate.status === 'DRAFT' || candidate.status === 'NEEDS_INPUT'">
|
||||
<view class="memory-head">
|
||||
<text class="memory-title">发现一条可保存的信息</text>
|
||||
<text class="memory-title">已帮你整理</text>
|
||||
<text class="memory-tag">{{ memoryTypeLabel }}</text>
|
||||
</view>
|
||||
|
||||
@@ -58,8 +50,8 @@
|
||||
<text class="row-value">{{ draft.summary || '待补充' }}</text>
|
||||
</view>
|
||||
<view class="memory-row">
|
||||
<text class="row-label">保存到</text>
|
||||
<text class="row-value">{{ targetLabel }}</text>
|
||||
<text class="row-label">保存范围</text>
|
||||
<text class="row-value">{{ assistantCandidate ? '由你确认' : targetLabel }}</text>
|
||||
</view>
|
||||
<view class="memory-row">
|
||||
<text class="row-label">记录时间</text>
|
||||
@@ -67,6 +59,8 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text v-if="optionalPrompt" class="optional-copy">{{ optionalPrompt }}</text>
|
||||
|
||||
<button
|
||||
class="reminder-switch"
|
||||
role="switch"
|
||||
@@ -83,14 +77,28 @@
|
||||
</view>
|
||||
</picker>
|
||||
|
||||
<text class="memory-note">确认后才会长期保存;暂不保存不会写入个人资料或项目记录。</text>
|
||||
<text class="memory-note">
|
||||
{{ assistantCandidate ? '仅自己保存不会提交公司;提交公司处理后进入企业流转。' : '确认后才会长期保存;暂不保存不会写入项目记录。' }}
|
||||
</text>
|
||||
<text v-if="errorText" class="memory-error">{{ errorText }}</text>
|
||||
|
||||
<view class="memory-actions">
|
||||
<button v-if="!editing" class="memory-action plain" :disabled="submitting" @click="editing = true">修改</button>
|
||||
<button v-else class="memory-action plain" :disabled="submitting" @click="editing = false">完成修改</button>
|
||||
<button class="memory-action outline" :disabled="submitting" @click="dismiss">暂不保存</button>
|
||||
<button class="memory-action primary" :disabled="submitting" @click="confirm">确认保存</button>
|
||||
<button
|
||||
v-if="assistantCandidate"
|
||||
class="memory-action scope private"
|
||||
:disabled="submitting"
|
||||
@click="confirm('PRIVATE')"
|
||||
>仅自己保存</button>
|
||||
<button
|
||||
v-if="assistantCandidate"
|
||||
class="memory-action scope company"
|
||||
:disabled="submitting"
|
||||
@click="confirm('COMPANY')"
|
||||
>提交公司处理</button>
|
||||
<button v-else class="memory-action primary" :disabled="submitting" @click="confirm()">确认保存</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -147,6 +155,7 @@ const editing = ref(false);
|
||||
const reminderEnabled = ref(false);
|
||||
const submitting = ref(false);
|
||||
const completed = ref(false);
|
||||
const confirmedTarget = ref('');
|
||||
const errorText = ref('');
|
||||
const idempotencyKey = ref(createMemoryIdempotencyKey(props.candidate.id));
|
||||
|
||||
@@ -158,17 +167,28 @@ const missingProjectLocationLabels = computed(() => [
|
||||
{ label: '单元', value: draft.value.unitName },
|
||||
{ label: '房号', value: draft.value.roomNo }
|
||||
].filter((item) => !item.value?.trim()).map((item) => item.label));
|
||||
const assistantCandidate = computed(() => props.candidate.targetDomain === 'ASSISTANT_CAPTURE');
|
||||
|
||||
const memoryTypeLabel = computed(() => ({
|
||||
RESIDENT_NEED: '住户需求',
|
||||
SERVICE_LEAD: '服务线索',
|
||||
RESIDENT_PROFILE: '住户画像',
|
||||
CASE: '优秀案例',
|
||||
PROJECT_NOTE: '工作记录',
|
||||
SERVICE_FACT: '服务事实',
|
||||
FOLLOW_UP: '待跟进事项',
|
||||
PERSONAL_NOTE: '个人事项'
|
||||
PERSONAL_NOTE: '个人想法'
|
||||
}[props.candidate.memoryType] || '工作事项'));
|
||||
|
||||
const targetLabel = computed(() =>
|
||||
props.candidate.targetDomain === 'PROJECT_SERVICE' ? '项目服务记录' : '我的资料与记忆'
|
||||
);
|
||||
const targetLabel = computed(() => ({
|
||||
PROJECT_SERVICE: '项目服务记录',
|
||||
PERSONAL: '仅自己可见',
|
||||
COMPANY: '公司处理中'
|
||||
}[confirmedTarget.value || props.candidate.targetDomain] || '我的资料与记忆'));
|
||||
|
||||
const completedCopy = computed(() => confirmedTarget.value === 'COMPANY'
|
||||
? '已提交公司处理,可在“我的资料与记忆”中查看流转状态。'
|
||||
: '这条信息已保存,后续工作助手可按权限查询。');
|
||||
|
||||
const terminalStatusTitle = computed(() => ({
|
||||
CONFIRMED: '这条事项已保存',
|
||||
@@ -176,7 +196,7 @@ const terminalStatusTitle = computed(() => ({
|
||||
EXPIRED: '这条确认卡已过期'
|
||||
}[props.candidate.status] || '这条确认卡已结束'));
|
||||
|
||||
const missingPrompt = computed(() => {
|
||||
const optionalPrompt = computed(() => {
|
||||
const labels: Record<string, string> = {
|
||||
projectCode: '所属项目',
|
||||
buildingName: '楼栋',
|
||||
@@ -187,7 +207,7 @@ const missingPrompt = computed(() => {
|
||||
occurredAt: '发生时间'
|
||||
};
|
||||
const fields = (props.candidate.missingFields || []).map((item) => labels[item] || item);
|
||||
return fields.length ? `请继续告诉我:${fields.join('、')}。信息补齐后再请你确认保存。` : '请继续补充对象或事项信息,信息补齐后再请你确认保存。';
|
||||
return fields.length ? `可继续补充:${fields.join('、')}(不影响先保存)` : '';
|
||||
});
|
||||
|
||||
const displayDate = (value: string | null) => value ? value.replace('T', ' ').slice(0, 16) : '未填写';
|
||||
@@ -204,14 +224,14 @@ const changeFollowUpDate = (event: { detail?: { value?: string } }) => {
|
||||
draft.value.followUpAt = value ? `${value}T09:00:00+08:00` : null;
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
const confirm = async (saveScope: '' | 'PRIVATE' | 'COMPANY' = '') => {
|
||||
if (submitting.value || completed.value) return;
|
||||
if (!draft.value.category || !draft.value.summary || !draft.value.occurredAt) {
|
||||
errorText.value = '请先补全事项、摘要和记录时间';
|
||||
editing.value = true;
|
||||
return;
|
||||
}
|
||||
if (props.candidate.targetDomain === 'PROJECT_SERVICE' && missingProjectLocationLabels.value.length) {
|
||||
if (!assistantCandidate.value && props.candidate.targetDomain === 'PROJECT_SERVICE' && missingProjectLocationLabels.value.length) {
|
||||
errorText.value = `项目服务记录还需补充:${missingProjectLocationLabels.value.join('、')}`;
|
||||
editing.value = true;
|
||||
return;
|
||||
@@ -231,10 +251,12 @@ const confirm = async () => {
|
||||
...draft.value,
|
||||
followUpAt: reminderEnabled.value ? draft.value.followUpAt : null
|
||||
},
|
||||
enableReminder: reminderEnabled.value
|
||||
enableReminder: reminderEnabled.value,
|
||||
saveScope: saveScope || undefined
|
||||
});
|
||||
if (requestAccountKey !== currentAccountKey()) return;
|
||||
completed.value = true;
|
||||
confirmedTarget.value = result.targetDomain;
|
||||
emit('confirmed', result);
|
||||
} catch (error) {
|
||||
errorText.value = error instanceof Error ? error.message : '保存失败,请稍后重试';
|
||||
@@ -267,6 +289,7 @@ watch(
|
||||
reminderEnabled.value = false;
|
||||
editing.value = false;
|
||||
completed.value = false;
|
||||
confirmedTarget.value = '';
|
||||
errorText.value = '';
|
||||
idempotencyKey.value = createMemoryIdempotencyKey(props.candidate.id);
|
||||
}
|
||||
@@ -451,7 +474,7 @@ watch(
|
||||
|
||||
.memory-note,
|
||||
.memory-error,
|
||||
.needs-input-copy,
|
||||
.optional-copy,
|
||||
.saved-copy {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
@@ -467,12 +490,20 @@ watch(
|
||||
color: #c8001a;
|
||||
}
|
||||
|
||||
.needs-input-copy,
|
||||
.optional-copy,
|
||||
.saved-copy {
|
||||
color: #596474;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.optional-copy {
|
||||
padding: 9px 10px;
|
||||
border-radius: 10px;
|
||||
background: #f7f8fa;
|
||||
color: #7a8491;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.memory-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
@@ -510,6 +541,20 @@ watch(
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.memory-action.scope {
|
||||
border: 1px solid #e60012;
|
||||
}
|
||||
|
||||
.memory-action.scope.private {
|
||||
background: #ffffff;
|
||||
color: #d70016;
|
||||
}
|
||||
|
||||
.memory-action.scope.company {
|
||||
background: #e60012;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.memory-card {
|
||||
padding: 14px;
|
||||
|
||||
Reference in New Issue
Block a user