front/src/views/h5/customer-center/components/H5PasswordSheet.vue
zzh 8155ba93d9 feat: 代发订单分轨与运营页,补 SPA 回退与 H5/下单优化
新增代发订单列表、扫码反查与拣货页,完善绑定/进度展示与 nginx/vite SPA 回退;同步 SKU 申报、价格发布跳过、字典与 H5 代发体验优化。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 10:27:37 +08:00

266 lines
5.6 KiB
Vue

<template>
<a-drawer
:visible="visible"
placement="bottom"
height="auto"
:footer="false"
:header="false"
unmount-on-close
:mask-closable="!saving"
:drawer-style="drawerStyle"
popup-container="body"
class="h5-pwd-drawer"
@cancel="close"
>
<div class="h5-pwd">
<div class="h5-pwd__handle" aria-hidden="true" />
<header class="h5-pwd__head">
<h3>{{ t('h5.me.resetPassword') }}</h3>
<button type="button" class="h5-pwd__close" :disabled="saving" @click="close">
<icon-close />
</button>
</header>
<div class="h5-pwd__body">
<section class="h5-pwd__card">
<label class="h5-pwd__label">{{ t('h5.me.oldPassword') }}</label>
<a-input-password v-model="form.oldPassword" allow-clear />
<label class="h5-pwd__label">{{ t('h5.me.newPassword') }}</label>
<a-input-password v-model="form.newPassword" allow-clear />
<label class="h5-pwd__label">{{ t('h5.me.confirmPassword') }}</label>
<a-input-password v-model="form.confirmPassword" allow-clear />
</section>
</div>
<footer class="h5-pwd__foot">
<button type="button" class="h5-pwd__btn" :disabled="saving" @click="submit">
<span v-if="saving" class="h5-pwd__loading" aria-hidden="true" />
{{ t('h5.me.save') }}
</button>
</footer>
</div>
</a-drawer>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { Message } from '@arco-design/web-vue';
import { IconClose } from '@arco-design/web-vue/es/icon';
import { AuthService } from '@/api/rbac';
defineOptions({ name: 'H5PasswordSheet' });
const props = defineProps<{
visible: boolean;
}>();
const emit = defineEmits<{
'update:visible': [value: boolean];
success: [];
}>();
const { t } = useI18n();
const saving = ref(false);
const form = reactive({ oldPassword: '', newPassword: '', confirmPassword: '' });
const drawerStyle = {
borderRadius: '20px 20px 0 0',
overflow: 'hidden',
maxHeight: 'min(92vh, 780px)',
};
function close() {
if (saving.value) return;
emit('update:visible', false);
}
async function submit() {
if (!form.oldPassword || !form.newPassword) {
Message.warning(t('h5.me.passwordRequired'));
return;
}
if (form.newPassword !== form.confirmPassword) {
Message.warning(t('h5.me.passwordMismatch'));
return;
}
saving.value = true;
try {
await AuthService.postRbacAuthChangePassword({
oldPassword: form.oldPassword,
newPassword: form.newPassword,
});
Message.success(t('h5.me.changePasswordSuccess'));
emit('update:visible', false);
emit('success');
} catch (e: any) {
Message.error(e?.message || t('h5.me.updateFailed'));
} finally {
saving.value = false;
}
}
watch(
() => props.visible,
(visible) => {
if (!visible) return;
form.oldPassword = '';
form.newPassword = '';
form.confirmPassword = '';
},
{ immediate: true },
);
</script>
<style lang="less">
.h5-pwd-drawer {
.arco-drawer-content {
border-radius: 20px 20px 0 0;
overflow: hidden;
max-height: min(92vh, 780px);
}
.arco-drawer-body {
padding: 0;
display: flex;
flex-direction: column;
max-height: min(92vh, 780px);
}
}
</style>
<style lang="less" scoped>
.h5-pwd {
display: flex;
flex-direction: column;
max-height: min(92vh, 780px);
background: #f5f7f8;
}
.h5-pwd__handle {
width: 36px;
height: 4px;
margin: 10px auto 0;
border-radius: 999px;
background: #c9cdd4;
}
.h5-pwd__head {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 48px;
h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #1d2129;
}
}
.h5-pwd__close {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
width: 36px;
height: 36px;
border: none;
border-radius: 10px;
background: transparent;
color: #86909c;
font-size: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
&:disabled {
opacity: 0.5;
}
}
.h5-pwd__body {
flex: 1;
min-height: 0;
overflow: auto;
padding: 0 16px 12px;
}
.h5-pwd__card {
background: #fff;
border-radius: 16px;
padding: 16px;
box-shadow: 0 4px 16px rgba(15, 23, 42, 0.04);
:deep(.arco-input-wrapper) {
background: #f7f8fa !important;
border: none !important;
box-shadow: none !important;
border-radius: 12px;
min-height: 44px;
}
:deep(.arco-input-wrapper.arco-input-focus) {
background: color-mix(in srgb, var(--app-primary-color) 8%, #fff) !important;
}
}
.h5-pwd__label {
display: block;
margin: 14px 0 8px;
font-size: 13px;
color: #4e5969;
&:first-child {
margin-top: 0;
}
}
.h5-pwd__foot {
padding: 12px 16px calc(14px + env(safe-area-inset-bottom, 0px));
background: #fff;
box-shadow: 0 -6px 20px rgba(15, 23, 42, 0.04);
}
.h5-pwd__btn {
width: 100%;
height: 48px;
border: none;
border-radius: 12px;
background: var(--app-primary-color);
color: #fff;
font-size: 15px;
font-weight: 600;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
cursor: pointer;
box-shadow: 0 8px 18px color-mix(in srgb, var(--app-primary-color) 28%, transparent);
&:disabled {
opacity: 0.7;
box-shadow: none;
}
}
.h5-pwd__loading {
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.35);
border-top-color: #fff;
border-radius: 50%;
animation: h5-pwd-spin 0.7s linear infinite;
}
@keyframes h5-pwd-spin {
to {
transform: rotate(360deg);
}
}
</style>