front/src/views/h5/customer-center/assistant/index.vue
zzh 2a4251f9db
All checks were successful
Build and Deploy Front / deploy (push) Successful in 5m51s
feat: H5 底栏与顾问体验、查价失败分组,以及下单/渠道与凭证加固
- H5:底栏 Liquid Dock 改版(图标/FAB 提示/badge)、订单详情操作图标化、空态与顾问侧栏样式
- Nana/官网:欢迎区与运单上下文、MCP 卡片示例;顾问 API 按环境直连 admin 网关
- 下单:电商平台改为字典下拉;9610 指南免税侧文案对齐汇总申报
- 查价:失败原因抽取并按步骤分组展示
- 渠道:重量因素数值排序、费用项防重复、取整区间重叠校验;分区匹配维度/模式显示中文
- 用户/仓储:OpenAPI 凭证仅客户门户主客户可见;打印控件下载链接抽公共常量并提示

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 09:13:12 +08:00

360 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="h5-assistant-page">
<!-- 查价预填上下文(运单上下文由 Shell 自带条展示) -->
<div v-if="priceContext" class="h5-ctx h5-enter">
<span class="h5-ctx__blob" aria-hidden="true" />
<div class="h5-ctx__main">
<strong>{{ t('h5.assistant.tip.priceTitle') }}</strong>
<span class="h5-ctx__desc">{{ priceContext }}</span>
</div>
<button type="button" class="h5-ctx__clear" @click="clearPriceContext">
{{ t('h5.assistant.clearContext') }}
</button>
</div>
<div class="h5-assistant-shell">
<AiAdvisorShell ref="shellRef" />
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import AiAdvisorShell from '@/components/NanaAssistant/AiAdvisorShell.vue';
import { parseWaybillContextFromQuery } from '@/composables/useAskAdvisor';
defineOptions({ name: 'H5Assistant' });
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const shellRef = ref<{ setInputText?: (text: string) => void } | null>(null);
const waybillCtx = computed(() => parseWaybillContextFromQuery(route.query));
const prefillText = computed(() => {
const raw = route.query.prefill;
const text = Array.isArray(raw) ? raw[0] : raw;
return typeof text === 'string' ? text.trim() : '';
});
const priceContext = computed(() => {
if (waybillCtx.value) return '';
return prefillText.value;
});
function clearPriceContext() {
const query = { ...route.query };
delete query.prefill;
router.replace({ path: '/h5/assistant', query });
shellRef.value?.setInputText?.('');
}
</script>
<style lang="less" scoped>
.h5-assistant-page {
height: calc(100dvh - var(--h5-dock-offset));
min-height: 360px;
padding: 10px 12px 8px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 8px;
background: #f5f6f8;
}
.h5-ctx {
position: relative;
z-index: 0;
overflow: hidden;
isolation: isolate;
display: flex;
align-items: center;
gap: 10px;
padding: 12px 12px 12px 14px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.78);
background: linear-gradient(
155deg,
rgba(255, 255, 255, 0.92) 0%,
rgba(255, 255, 255, 0.7) 100%
);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.9),
0 6px 16px color-mix(in srgb, var(--app-primary-color) 10%, transparent);
flex-shrink: 0;
}
.h5-ctx__blob {
position: absolute;
z-index: 0;
inset: -50% -10% auto auto;
width: 70%;
height: 140%;
border-radius: 42% 58% 48% 52% / 48% 42% 58% 52%;
background:
radial-gradient(
circle at 70% 60%,
color-mix(in srgb, var(--app-primary-color) 18%, transparent) 0%,
transparent 58%
);
filter: blur(12px);
opacity: 0.7;
pointer-events: none;
}
.h5-ctx__main {
position: relative;
z-index: 1;
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 3px;
strong {
font-size: 13px;
font-weight: 700;
color: var(--app-primary-color);
}
}
.h5-ctx__desc {
font-size: 12px;
color: #4e5969;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.h5-ctx__clear {
position: relative;
z-index: 1;
flex-shrink: 0;
border: none;
height: 28px;
padding: 0 10px;
border-radius: 14px;
background: rgba(15, 23, 42, 0.05);
color: #86909c;
font-size: 12px;
font-weight: 600;
cursor: pointer;
}
.h5-assistant-shell {
position: relative;
flex: 1;
min-height: 0;
border-radius: 18px;
overflow: hidden;
background: rgba(255, 255, 255, 0.55);
border: 1px solid rgba(255, 255, 255, 0.78);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.85),
0 8px 24px rgba(15, 23, 42, 0.05);
display: flex;
flex-direction: column;
:deep(.ai-advisor-root),
:deep(.ai-advisor-shell),
:deep(.ai-advisor-app),
:deep(.ai-advisor-layout) {
position: relative;
height: 100%;
min-height: 0;
}
/* H5:去掉 PC 返回,底栏已够导航 */
:deep(.ai-app-bar__back),
:deep(.ai-waybill-context__back) {
display: none !important;
}
:deep(.ai-advisor-shell--page .ai-advisor-layout) {
padding: 0;
max-width: none;
}
:deep(.ai-shell-bg) {
display: none;
}
:deep(.ai-advisor-app) {
border: none;
border-radius: 0;
box-shadow: none;
background: transparent;
backdrop-filter: none;
-webkit-backdrop-filter: none;
padding: 8px 10px 10px;
}
:deep(.ai-history-sidebar) {
position: absolute;
top: 0;
left: 0;
bottom: 0;
z-index: 20;
width: min(280px, 86%);
border-radius: 0 18px 18px 0;
}
/* 透明可点区域:点侧栏外关闭,但不加灰色遮罩 */
:deep(.ai-advisor-shell.ai-history-open .ai-history-backdrop) {
display: block !important;
position: absolute !important;
inset: 0 !important;
z-index: 19 !important;
border: none;
background: transparent !important;
cursor: pointer;
}
/* 运单上下文:移动端更紧凑 */
:deep(.ai-waybill-context) {
margin: 0 0 8px;
padding: 10px 12px;
border-radius: 12px;
border: none;
background: color-mix(in srgb, var(--app-primary-color) 10%, #fff);
color: #1d2129;
}
:deep(.ai-waybill-context__actions) {
gap: 6px;
}
:deep(.ai-waybill-context__link),
:deep(.ai-waybill-context__btn),
:deep(.ai-waybill-context__clear) {
height: 28px;
border-radius: 14px;
font-size: 12px;
}
:deep(.ai-waybill-context__clear) {
color: #86909c;
}
:deep(.ai-waybill-context svg) {
color: var(--app-primary-color);
}
/* 欢迎区 + 快捷入口 */
:deep(.ai-welcome__hero) {
padding: 8px 2px 12px;
gap: 10px;
}
:deep(.ai-welcome__avatar.nana-fab-wrap) {
width: 48px;
height: 48px;
}
:deep(.ai-welcome__hero h2) {
font-size: 1.08rem;
}
:deep(.ai-welcome__hero p) {
font-size: 0.82rem;
color: var(--color-text-3, #86909c);
}
:deep(.ai-mcp-grid) {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
:deep(.ai-mcp-grid--waybill) {
grid-template-columns: 1fr 1fr;
}
:deep(.ai-mcp-card) {
background: transparent;
box-shadow: none;
min-height: 96px;
padding: 16px 12px;
border-radius: 12px;
border: 1px solid rgba(15, 23, 42, 0.08);
}
:deep(.ai-followup) {
gap: 6px;
padding: 0 0 6px;
}
:deep(.ai-followup-chip) {
border: none;
background: rgba(15, 23, 42, 0.04);
border-radius: 14px;
}
:deep(.ai-composer) {
border-radius: 16px;
}
:deep(.ai-composer-send) {
width: 40px;
height: 40px;
border-radius: 12px;
background: var(--app-primary-color);
color: #fff;
opacity: 1;
.arco-icon,
svg {
width: 1.15em;
height: 1.15em;
color: #fff;
fill: currentColor;
}
&:disabled {
background: #e5e6eb;
color: #c9cdd4;
opacity: 1;
cursor: not-allowed;
.arco-icon,
svg {
color: #c9cdd4;
}
}
&:not(:disabled):active {
filter: brightness(1.05);
}
}
:deep(.ai-composer-footer) {
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 8px;
}
:deep(.ai-composer-hint) {
font-size: 11px;
color: #86909c;
opacity: 0.72;
}
:deep(.ai-msg-row--assistant .ai-msg-bubble) {
color: #1d2129;
}
:deep(.ai-composer-input) {
color: #1d2129;
}
:deep(.ai-msg-bubble) {
border-radius: 14px;
}
}
</style>