|
@@ -0,0 +1,478 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import useClipboard from 'vue-clipboard3';
|
|
|
+import { ElMessage } from 'element-plus';
|
|
|
+import { genSpAuthLink } from '/@/views/store-manage/market-store/api';
|
|
|
+import { Check, CircleCheck, Key, Shop, Warning, Link } from '@element-plus/icons-vue';
|
|
|
+
|
|
|
+
|
|
|
+const { toClipboard } = useClipboard();
|
|
|
+const authorizeDialogVisible = defineModel();
|
|
|
+
|
|
|
+const formData = ref({
|
|
|
+ countryCode: 'US',
|
|
|
+ accountName: '',
|
|
|
+ platformCode: '',
|
|
|
+});
|
|
|
+
|
|
|
+const authType = ref('sp');
|
|
|
+const authLink = ref('');
|
|
|
+const isGenerating = ref(false);
|
|
|
+const isCopying = ref(false);
|
|
|
+
|
|
|
+const countryCodeOptions = [
|
|
|
+ // 美洲
|
|
|
+ { label: '美国', value: 'US', flag: '🇺🇸' },
|
|
|
+ { label: '加拿大', value: 'CA', flag: '🇨🇦' },
|
|
|
+ { label: '墨西哥', value: 'MX', flag: '🇲🇽' },
|
|
|
+
|
|
|
+ // 欧洲
|
|
|
+ { label: '英国', value: 'UK', flag: '🇬🇧' }, // 注意:UK是保留代码,正式ISO代码是GB
|
|
|
+ { label: '德国', value: 'DE', flag: '🇩🇪' },
|
|
|
+ { label: '法国', value: 'FR', flag: '🇫🇷' },
|
|
|
+ { label: '意大利', value: 'IT', flag: '🇮🇹' },
|
|
|
+ { label: '西班牙', value: 'ES', flag: '🇪🇸' },
|
|
|
+ { label: '荷兰', value: 'NL', flag: '🇳🇱' },
|
|
|
+ { label: '瑞典', value: 'SE', flag: '🇸🇪' },
|
|
|
+ { label: '瑞士', value: 'CH', flag: '🇨🇭' },
|
|
|
+ { label: '比利时', value: 'BE', flag: '🇧🇪' },
|
|
|
+ { label: '波兰', value: 'PL', flag: '🇵🇱' },
|
|
|
+
|
|
|
+ // 其他地区
|
|
|
+ { label: '日本', value: 'JP', flag: '🇯🇵' },
|
|
|
+ { label: '澳大利亚', value: 'AU', flag: '🇦🇺' },
|
|
|
+ { label: '新加坡', value: 'SG', flag: '🇸🇬' },
|
|
|
+ { label: '沙特阿拉伯', value: 'SA', flag: '🇸🇦' },
|
|
|
+ { label: '阿联酋', value: 'AE', flag: '🇦🇪' }
|
|
|
+];
|
|
|
+
|
|
|
+
|
|
|
+// 表单验证规则
|
|
|
+const formRules = {
|
|
|
+ accountName: [
|
|
|
+ { required: true, message: '请输入店铺名称', trigger: 'blur' },
|
|
|
+ { min: 2, max: 50, message: '店铺名称长度在 2 到 50 个字符', trigger: 'blur' },
|
|
|
+ ],
|
|
|
+ platformCode: [
|
|
|
+ { required: true, message: '请输入平台编号', trigger: 'blur' },
|
|
|
+ { pattern: /^[A-Za-z0-9-_]+$/, message: '平台编号只能包含字母、数字、短划线和下划线', trigger: 'blur' },
|
|
|
+ ],
|
|
|
+ countryCode: [{ required: true, message: '请选择店铺区域', trigger: 'change' }],
|
|
|
+};
|
|
|
+
|
|
|
+// 生成授权链接
|
|
|
+const genAuthLink = async () => {
|
|
|
+ const form = formRef.value;
|
|
|
+ if (!form) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const valid = await form.validate();
|
|
|
+ if (!valid) return;
|
|
|
+
|
|
|
+ isGenerating.value = true;
|
|
|
+
|
|
|
+ if (authType.value === 'sp') {
|
|
|
+ const resp = await genSpAuthLink(formData.value);
|
|
|
+ authLink.value = resp.data;
|
|
|
+
|
|
|
+ ElMessage({
|
|
|
+ message: '授权链接生成成功!',
|
|
|
+ type: 'success',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('生成授权链接失败:', error);
|
|
|
+ ElMessage({
|
|
|
+ message: error.message || '生成授权链接失败,请重试',
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ isGenerating.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 复制链接
|
|
|
+const copyLink = async () => {
|
|
|
+ if (!authLink.value) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ isCopying.value = true;
|
|
|
+ await toClipboard(authLink.value);
|
|
|
+
|
|
|
+ ElMessage({
|
|
|
+ message: '链接复制成功!',
|
|
|
+ type: 'success',
|
|
|
+ duration: 2000,
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('复制失败:', error);
|
|
|
+ ElMessage({
|
|
|
+ message: '复制失败,请手动复制',
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ isCopying.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const formRef = ref(null);
|
|
|
+
|
|
|
+// 重置表单
|
|
|
+const resetForm = () => {
|
|
|
+ authLink.value = '';
|
|
|
+ isGenerating.value = false;
|
|
|
+ isCopying.value = false;
|
|
|
+ formRef.value?.resetFields();
|
|
|
+};
|
|
|
+
|
|
|
+// 表单是否有效
|
|
|
+const isFormValid = computed(() => {
|
|
|
+ return formData.value.accountName.trim() !== '' && formData.value.platformCode.trim() !== '' && formData.value.countryCode;
|
|
|
+});
|
|
|
+
|
|
|
+// 在浏览器中打开链接
|
|
|
+const openInBrowser = () => {
|
|
|
+ if (authLink.value) {
|
|
|
+ window.open(authLink.value, '_blank');
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <el-dialog
|
|
|
+ v-model="authorizeDialogVisible"
|
|
|
+ width="520px"
|
|
|
+ :destroy-on-close="true"
|
|
|
+ @closed="resetForm"
|
|
|
+ center
|
|
|
+ class="auth-dialog"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <template #title>
|
|
|
+ <div class="dialog-header">
|
|
|
+ <span class="title-text">
|
|
|
+ {{ authType === 'sp' ? '亚马逊店铺SP授权' : '广告授权' }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="dialog-content">
|
|
|
+ <el-form ref="formRef" :model="formData" :rules="formRules" label-position="top" class="auth-form" @submit.prevent>
|
|
|
+ <el-form-item label="店铺名称" prop="accountName">
|
|
|
+ <el-input v-model="formData.accountName" placeholder="请输入您的亚马逊店铺名称,例如:Amazon-ASJ-AE" clearable maxlength="50" show-word-limit>
|
|
|
+ <template #prefix>
|
|
|
+ <el-icon>
|
|
|
+ <Shop />
|
|
|
+ </el-icon>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="平台编号" prop="platformCode">
|
|
|
+ <el-input v-model="formData.platformCode" placeholder="请输入平台分配的唯一编号,例如:ZS86" clearable maxlength="30">
|
|
|
+ <template #prefix>
|
|
|
+ <el-icon>
|
|
|
+ <Key />
|
|
|
+ </el-icon>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="店铺区域" prop="countryCode">
|
|
|
+ <el-select v-model="formData.countryCode" placeholder="请选择店铺所在区域" style="width: 100%" clearable>
|
|
|
+ <el-option v-for="option in countryCodeOptions" :key="option.value" :label="option.label" :value="option.value">
|
|
|
+ <span class="option-content">
|
|
|
+ <span class="flag">{{ option.flag }}</span>
|
|
|
+ <span>{{ option.label }}</span>
|
|
|
+ </span>
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div class="action-area">
|
|
|
+ <el-button type="primary" @click="genAuthLink" :disabled="!isFormValid" :loading="isGenerating" class="generate-btn" size="large">
|
|
|
+ <el-icon v-if="!isGenerating">
|
|
|
+ <Link />
|
|
|
+ </el-icon>
|
|
|
+ {{ isGenerating ? '生成中...' : '生成授权链接' }}
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <div v-show="authLink" class="link-area">
|
|
|
+ <el-divider>
|
|
|
+ <el-icon color="#67c23a">
|
|
|
+ <Check />
|
|
|
+ </el-icon>
|
|
|
+ </el-divider>
|
|
|
+
|
|
|
+ <div class="success-tip">
|
|
|
+ <el-icon color="#67c23a" size="20">
|
|
|
+ <CircleCheck />
|
|
|
+ </el-icon>
|
|
|
+ <span>授权链接已生成!请在常用浏览器中打开进行授权</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="link-container">
|
|
|
+ <el-input :model-value="authLink" readonly class="link-input">
|
|
|
+ <template #prefix>
|
|
|
+ <el-icon>
|
|
|
+ <Link />
|
|
|
+ </el-icon>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+
|
|
|
+ <div class="link-actions">
|
|
|
+ <el-button type="success" @click="copyLink" :loading="isCopying" icon="DocumentCopy" class="action-btn">
|
|
|
+ {{ isCopying ? '复制中...' : '复制' }}
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <el-button type="primary" @click="openInBrowser" icon="TopRight" class="action-btn"> 打开 </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="warning-tip">
|
|
|
+ <el-icon color="#e6a23c">
|
|
|
+ <Warning />
|
|
|
+ </el-icon>
|
|
|
+ <span>请确保在安全的网络环境下进行授权操作</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.auth-dialog {
|
|
|
+ border-radius: 12px;
|
|
|
+ box-shadow: 0 12px 32px 4px rgba(0, 0, 0, 0.12);
|
|
|
+}
|
|
|
+
|
|
|
+.auth-dialog :deep(.el-dialog__header) {
|
|
|
+ padding: 24px 24px 0;
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-dialog :deep(.el-dialog__body) {
|
|
|
+ padding: 0 24px 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.dialog-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.header-icon {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ background: linear-gradient(135deg, #409eff, #67c23a);
|
|
|
+ border-radius: 50%;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
+.title-text {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+
|
|
|
+.dialog-content {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-form {
|
|
|
+ margin-bottom: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-form :deep(.el-form-item__label) {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-form :deep(.el-form-item) {
|
|
|
+ margin-bottom: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-form :deep(.el-input__wrapper) {
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-form :deep(.el-input__wrapper:hover) {
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
+}
|
|
|
+
|
|
|
+.auth-form :deep(.el-select .el-input__wrapper) {
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.option-content {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.flag {
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.action-area {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.generate-btn {
|
|
|
+ width: 100%;
|
|
|
+ height: 48px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: linear-gradient(135deg, #409eff, #67c23a);
|
|
|
+ border: none;
|
|
|
+ box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.generate-btn:hover:not(:disabled) {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ box-shadow: 0 6px 16px rgba(64, 158, 255, 0.4);
|
|
|
+}
|
|
|
+
|
|
|
+.generate-btn:disabled {
|
|
|
+ background: #c0c4cc;
|
|
|
+ box-shadow: none;
|
|
|
+ cursor: not-allowed;
|
|
|
+}
|
|
|
+
|
|
|
+.link-area {
|
|
|
+ width: 100%;
|
|
|
+ margin-top: 24px;
|
|
|
+ animation: fadeInUp 0.5s ease;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes fadeInUp {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(20px);
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.success-tip {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ padding: 12px;
|
|
|
+ background: linear-gradient(135deg, #f0f9ff, #e6f7ff);
|
|
|
+ border-radius: 8px;
|
|
|
+ color: #52c41a;
|
|
|
+ font-weight: 500;
|
|
|
+ border: 1px solid #b7eb8f;
|
|
|
+}
|
|
|
+
|
|
|
+.link-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.link-input :deep(.el-input__wrapper) {
|
|
|
+ background-color: #f8fafc;
|
|
|
+ border: 1px dashed #d1d5db;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.link-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 8px;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.action-btn {
|
|
|
+ flex: 1;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-weight: 500;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.action-btn:hover {
|
|
|
+ transform: translateY(-1px);
|
|
|
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.warning-tip {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 6px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ background: #fdf6ec;
|
|
|
+ border-radius: 6px;
|
|
|
+ color: #e6a23c;
|
|
|
+ font-size: 13px;
|
|
|
+ border: 1px solid #f5dab1;
|
|
|
+}
|
|
|
+
|
|
|
+.el-divider {
|
|
|
+ margin: 20px 0 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-divider :deep(.el-divider__text) {
|
|
|
+ background: white;
|
|
|
+ padding: 0 12px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 响应式设计 */
|
|
|
+@media (max-width: 480px) {
|
|
|
+ .auth-dialog {
|
|
|
+ width: 90vw !important;
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .link-actions {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-btn {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 暗色模式支持 */
|
|
|
+@media (prefers-color-scheme: dark) {
|
|
|
+ .dialog-header .title-text {
|
|
|
+ color: #e5eaf3;
|
|
|
+ }
|
|
|
+
|
|
|
+ .success-tip {
|
|
|
+ background: linear-gradient(135deg, #0c1420, #1a2332);
|
|
|
+ border-color: #2d5a27;
|
|
|
+ color: #73d13d;
|
|
|
+ }
|
|
|
+
|
|
|
+ .warning-tip {
|
|
|
+ background: #2d1b12;
|
|
|
+ border-color: #594214;
|
|
|
+ color: #faad14;
|
|
|
+ }
|
|
|
+
|
|
|
+ .link-input :deep(.el-input__wrapper) {
|
|
|
+ background-color: #1d2329;
|
|
|
+ border-color: #4c5155;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|