front/src/views/h5/customer-center/assistant/index.vue
zzh abfca7a21a feat: add H5 customer center, marketing admin, and employee profile UX
Ship customer portal and marketing pages, user edit drawer with employee archive, IDE employee numbers, channel config refactor, and related nginx/route updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-26 23:44:02 +08:00

321 lines
6.7 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 - 56px - env(safe-area-inset-bottom, 0px));
min-height: 360px;
padding: 10px 12px 8px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 8px;
background: linear-gradient(
180deg,
color-mix(in srgb, var(--app-primary-color) 12%, #f5f7f8) 0%,
#f5f7f8 140px
);
}
.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 {
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) {
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) {
border-radius: 0 18px 18px 0;
}
/* 运单上下文:移动端更紧凑 */
: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: 14px 0 12px;
}
:deep(.ai-welcome__hero h2) {
font-size: 1.15rem;
}
:deep(.ai-welcome__hero p) {
font-size: 0.84rem;
}
:deep(.ai-quick-grid) {
grid-template-columns: 1fr 1fr;
gap: 8px;
}
:deep(.ai-quick-card) {
border-radius: 14px;
padding: 12px 10px;
min-height: 64px;
}
: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;
}
:deep(.ai-msg-bubble) {
border-radius: 14px;
}
}
</style>