mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-11-10 02:49:03 +08:00
refactor(layout): 重构商家后台布局与导航结构
- 移除多标签页内嵌模式,详情页固定在新窗口打开 - 重构顶部栏与侧边栏布局,Logo 移至顶部栏区域 - 新增未读消息角标,与消息页面实时同步数量 - 新增面包屑路径栏替代静态页面标题展示 - 删除页面配置抽屉和菜单搜索组件 - 将发货与退货地址设置拆分为独立页面(店铺信息、地址管理) - 增加 Logo 加载失败回退及 favicon 健壮性处理 - 注册店铺信息与地址管理页面的显式懒加载映射
This commit is contained in:
@@ -87,6 +87,11 @@ export const getShopInfo = () => {
|
||||
return getRequest(`/settings/storeSettings`)
|
||||
}
|
||||
|
||||
// 获取商家入驻详细信息
|
||||
export const getShopEntryDetail = () => {
|
||||
return getRequest(`/settings/storeSettings/storeDetail`)
|
||||
}
|
||||
|
||||
// 保存商家详细信息
|
||||
export const saveShopInfo = (params) => {
|
||||
return putRequest(`/settings/storeSettings`, params)
|
||||
@@ -127,5 +132,3 @@ export const editShipTemplate = (id, params, headers) => {
|
||||
export const editChecked = (logisticsId,params) => {
|
||||
return putRequest(`/other/logistics/${logisticsId}/updateStoreLogistics`,params)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,6 @@ module.exports = {
|
||||
*/
|
||||
mainColor: "#ff5c58", //主题色
|
||||
setting: {
|
||||
isUseTabsRouter: false, // 多标签页内嵌模式默认关闭,用户可在页面配置中开启。
|
||||
isUseTabsRouter: false, // 商家后台固定关闭多标签页内嵌模式,详情使用新页面展示。
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"setting": {
|
||||
"isUseTabsRouter": true,
|
||||
"isUseTabsRouter": false,
|
||||
"showFooter": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
export default (url) =>()=>import(`@/views/${url}.vue`)
|
||||
const explicitViews = {
|
||||
"shop/shopInfo": () => import("@/views/shop/shopInfo.vue"),
|
||||
"shop/addressManage": () => import("@/views/shop/addressManage.vue"),
|
||||
};
|
||||
|
||||
export default (url) => explicitViews[url] || (() => import(`@/views/${url}.vue`));
|
||||
|
||||
@@ -489,6 +489,24 @@ export const result = [{
|
||||
component: "shop/shopSetting",
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
name: "shopInfo",
|
||||
level: 2,
|
||||
type: 0,
|
||||
title: "店铺信息",
|
||||
path: "shopInfo",
|
||||
component: "shop/shopInfo",
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
name: "addressManage",
|
||||
level: 2,
|
||||
type: 0,
|
||||
title: "地址管理",
|
||||
path: "addressManage",
|
||||
component: "shop/addressManage",
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
name: "wapList",
|
||||
level: 2,
|
||||
|
||||
@@ -27,8 +27,13 @@ export const useAppStore = defineStore("app", {
|
||||
routers: [otherRouter],
|
||||
tagsList: [...otherRouter.children],
|
||||
refMenu: "",
|
||||
unreadMessageCount: 0,
|
||||
}),
|
||||
actions: {
|
||||
/** 更新顶部未读消息数量。 */
|
||||
setUnreadMessageCount(count) {
|
||||
this.unreadMessageCount = Math.max(0, Number(count) || 0);
|
||||
},
|
||||
/** 清理账号绑定的路由与标签目录,保留静态页面,防止切换账号后复用旧菜单。 */
|
||||
resetNavigationRoutes() {
|
||||
this.routers = [otherRouter];
|
||||
|
||||
@@ -7,11 +7,13 @@ const localSetting = window.localStorage.getItem("setting");
|
||||
|
||||
export const useSettingStore = defineStore("setting", {
|
||||
state: () => ({
|
||||
setting: localSetting ? JSON.parse(localSetting) : setting,
|
||||
// 兼容已保存的其他偏好,旧浏览器中的多标签开启状态统一归为关闭。
|
||||
setting: { ...setting, ...(localSetting ? JSON.parse(localSetting) : {}), isUseTabsRouter: false },
|
||||
}),
|
||||
actions: {
|
||||
/** 更新其他页面偏好时,仍保持商家多标签模式关闭。 */
|
||||
updateSetting(data) {
|
||||
this.setting = data;
|
||||
this.setting = { ...data, isUseTabsRouter: false };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@ export const useUserStore = defineStore("user", {
|
||||
appStore.updateMenulist([]);
|
||||
appStore.setCurrNav("");
|
||||
appStore.setAdded(false);
|
||||
appStore.setUnreadMessageCount(0);
|
||||
appStore.resetNavigationRoutes();
|
||||
appStore.storeOpenedList = [{ title: "首页", path: "", name: "home_index" }];
|
||||
},
|
||||
|
||||
@@ -51,21 +51,12 @@ export function enCode(v1) {
|
||||
|
||||
import {router} from "@/router/index";
|
||||
/**
|
||||
* 自定义跳转
|
||||
* 打开详情页面;商家后台固定关闭多标签页内嵌模式,不再读取旧浏览器偏好。
|
||||
* @param push Vue Router 路由位置
|
||||
*/
|
||||
export function customRouterPush(push){
|
||||
const setting = window.localStorage.getItem('setting') ? JSON.parse(window.localStorage.getItem('setting')) : {};
|
||||
|
||||
if(setting.isUseTabsRouter){
|
||||
router.push(push)
|
||||
}
|
||||
else{
|
||||
if(Object.keys(setting).length == 0){router.push(push)}
|
||||
else{
|
||||
let url = router.resolve(push);
|
||||
window.open(url.href, '_blank');
|
||||
}
|
||||
}
|
||||
const url = router.resolve(push);
|
||||
window.open(url.href, '_blank');
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,29 +5,44 @@
|
||||
<template>
|
||||
<div class="main">
|
||||
<div class="sidebar-menu-con menu-bar">
|
||||
<div class="logo-con">
|
||||
<img alt="店铺 Logo" :src="storeSideLogo" key="max-logo" />
|
||||
<span class="brand-caption">商家工作台</span>
|
||||
</div>
|
||||
<shrinkable-menu />
|
||||
</div>
|
||||
<div class="main-header-con" :style="{ height: setting.isUseTabsRouter ? '106px' : '60px' }">
|
||||
<div class="main-header-con">
|
||||
<div class="logo-con">
|
||||
<img alt="平台 Logo" :src="storeSideLogo" key="max-logo" @error="onLogoError" />
|
||||
</div>
|
||||
<div class="main-header">
|
||||
<div class="header-avator-con">
|
||||
<div class="header-page-info">
|
||||
<span class="workspace-label">商家后台</span>
|
||||
<span class="header-divider">/</span>
|
||||
<strong>{{ currentPageTitle }}</strong>
|
||||
</div>
|
||||
<div class="user-dropdown-menu-con">
|
||||
<el-row
|
||||
justify="end"
|
||||
align="middle"
|
||||
class="user-dropdown-innercon"
|
||||
>
|
||||
<menu-search />
|
||||
<store-qrcode />
|
||||
<ul class="nav-list">
|
||||
<li class="nav-item">
|
||||
<el-tooltip
|
||||
:content="unreadMessageCount > 0 ? `有 ${unreadMessageCount} 条未读消息` : '暂无未读消息'"
|
||||
placement="bottom"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="header-icon-button header-message-btn"
|
||||
:aria-label="unreadMessageCount > 0 ? `有 ${unreadMessageCount} 条未读消息` : '消息中心'"
|
||||
@click="openMessagePage"
|
||||
>
|
||||
<el-badge
|
||||
:value="unreadMessageCount"
|
||||
:max="99"
|
||||
:hidden="unreadMessageCount <= 0"
|
||||
class="header-message-badge"
|
||||
>
|
||||
<el-icon :size="18"><Bell /></el-icon>
|
||||
</el-badge>
|
||||
</button>
|
||||
</el-tooltip>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<el-tooltip content="联系客服" placement="bottom">
|
||||
<el-button type="warning" size="small" :loading="load" @click="im">
|
||||
@@ -36,13 +51,6 @@
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<el-tooltip content="设置" placement="bottom">
|
||||
<button type="button" class="header-icon-button" aria-label="页面设置" @click="handleClickSetting">
|
||||
<el-icon :size="17"><Setting /></el-icon>
|
||||
</button>
|
||||
</el-tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
<el-dropdown trigger="hover" @command="handleClickUserDropdown">
|
||||
<div class="dropList">
|
||||
@@ -66,17 +74,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tags-con" v-if="setting.isUseTabsRouter">
|
||||
<tags-page-opened :pageTagsList="pageTagsList" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="single-page-con"
|
||||
:style="{
|
||||
top: setting.isUseTabsRouter ? '106px' : '60px',
|
||||
height: setting.isUseTabsRouter ? 'calc(100% - 116px)' : 'calc(100% - 70px)',
|
||||
}"
|
||||
>
|
||||
<div class="single-page-con">
|
||||
<div class="page-path-bar">
|
||||
<div class="header-page-info">
|
||||
<template v-for="(part, index) in currentPathParts" :key="index">
|
||||
<span v-if="index > 0" class="header-divider">/</span>
|
||||
<strong v-if="index === currentPathParts.length - 1">{{ part }}</strong>
|
||||
<span v-else class="workspace-label">{{ part }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="single-page">
|
||||
<router-view v-slot="{ Component }">
|
||||
<component :is="Component" v-if="Component" :key="$route.fullPath" />
|
||||
@@ -84,52 +92,77 @@
|
||||
</div>
|
||||
</div>
|
||||
<circleLoading class="loading-position" v-show="loading" />
|
||||
<configDrawer ref="configRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { ChatDotRound, Setting, UserFilled } from "@element-plus/icons-vue";
|
||||
import { Bell, ChatDotRound, UserFilled } from "@element-plus/icons-vue";
|
||||
import shrinkableMenu from "./main-components/shrinkable-menu/shrinkable-menu.vue";
|
||||
import tagsPageOpened from "./main-components/tags-page-opened.vue";
|
||||
import circleLoading from "@/views/my-components/lili/circle-loading.vue";
|
||||
import configDrawer from "@/views/main-components/config-drawer.vue";
|
||||
import storeQrcode from "@/views/main-components/store-qrcode.vue";
|
||||
import menuSearch from "@/views/main-components/menu-search.vue";
|
||||
import Cookies from "js-cookie";
|
||||
import util from "@/libs/util.js";
|
||||
import { logout } from "@/api/index";
|
||||
import { flattenNavigation, findNavigationItem } from "@/libs/seller-navigation";
|
||||
import defaultLogo from "@/assets/logo.png";
|
||||
import { loadSiteSettings } from "@/composables/useSiteSettings";
|
||||
import { getMessageSendData, logout, userMsg } from "@/api/index";
|
||||
import { getIMDetail } from "@/api/common";
|
||||
import { userMsg } from "@/api/index";
|
||||
import { Message } from "@/utils/message";
|
||||
import { getStore, setStore } from "@/libs/storage";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { useSettingStore } from "@/stores/setting";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
const configRef = ref(null);
|
||||
const sliceNum = ref(5);
|
||||
const userInfo = ref({});
|
||||
const storeSideLogo = ref("");
|
||||
const storeSideLogo = ref(defaultLogo);
|
||||
const IMLink = ref("");
|
||||
const load = ref(false);
|
||||
|
||||
const setting = computed(() => settingStore.setting);
|
||||
const loading = computed(() => appStore.loading);
|
||||
const unreadMessageCount = computed(() => appStore.unreadMessageCount);
|
||||
const pageTagsList = computed(() => appStore.storeOpenedList);
|
||||
const currentPageTitle = computed(() => route.meta.title || pageTagsList.value.find((item) => item.name === route.name)?.title || '工作台');
|
||||
const navigationItems = computed(() => flattenNavigation(appStore.navigationMenus || []));
|
||||
const currentPathParts = computed(() => {
|
||||
const matched = findNavigationItem(navigationItems.value, route.name);
|
||||
const rawParts = matched
|
||||
? [
|
||||
matched.topTitle,
|
||||
matched.groupTitle,
|
||||
matched.title,
|
||||
route.name !== matched.name ? currentPageTitle.value : "",
|
||||
]
|
||||
: ["商家后台", currentPageTitle.value];
|
||||
return rawParts.filter((part, idx, arr) => part && part !== arr[idx - 1]);
|
||||
});
|
||||
const lang = computed(() => appStore.lang);
|
||||
|
||||
function handleClickSetting() {
|
||||
configRef.value.open();
|
||||
/**
|
||||
* 跳转至系统消息页面。
|
||||
*/
|
||||
function openMessagePage() {
|
||||
util.openNewPage("message_index");
|
||||
router.push({ name: "message_index" });
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取当前店铺未读消息总数,更新右上角消息角标。
|
||||
*/
|
||||
function loadUnreadMessageCount() {
|
||||
getMessageSendData({ status: "UN_READY", pageNumber: 1, pageSize: 1 })
|
||||
.then((res) => {
|
||||
if (res && res.success && res.result) {
|
||||
appStore.setUnreadMessageCount(res.result.total);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
async function im() {
|
||||
@@ -152,23 +185,67 @@ async function getIMDetailMethods() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新页面站点图标。
|
||||
* @param {string} href 图标地址
|
||||
*/
|
||||
function applyFavicon(href) {
|
||||
if (!href || href === "undefined" || href === "null") return;
|
||||
const link =
|
||||
document.querySelector("link[rel*='icon']") ||
|
||||
document.createElement("link");
|
||||
link.type = "image/x-icon";
|
||||
link.href = href;
|
||||
link.rel = "shortcut icon";
|
||||
document.getElementsByTagName("head")[0].appendChild(link);
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台 Logo 加载失败时回退为默认 Logo。
|
||||
* @param {Event} e 图片加载错误事件
|
||||
*/
|
||||
function onLogoError(e) {
|
||||
if (e?.target && e.target.src !== defaultLogo) {
|
||||
e.target.src = defaultLogo;
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
const pathArr = util.setCurrentPath(route.name);
|
||||
if (pathArr.length >= 2) {
|
||||
appStore.addOpenSubmenu(pathArr[1].name);
|
||||
}
|
||||
storeSideLogo.value = localStorage.getItem("sellerlogoImg");
|
||||
const cachedLogo = localStorage.getItem("sellerlogoImg");
|
||||
storeSideLogo.value =
|
||||
cachedLogo && cachedLogo !== "undefined" && cachedLogo !== "null"
|
||||
? cachedLogo
|
||||
: defaultLogo;
|
||||
util.title(currentPageTitle.value);
|
||||
const link =
|
||||
document.querySelector("link[rel*='icon']") ||
|
||||
document.createElement("link");
|
||||
link.type = "image/x-icon";
|
||||
link.href = localStorage.getItem("sellerIconImg");
|
||||
link.rel = "shortcut icon";
|
||||
document.getElementsByTagName("head")[0].appendChild(link);
|
||||
applyFavicon(localStorage.getItem("sellerIconImg"));
|
||||
|
||||
loadSiteSettings()
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
const logo = data.storeSideLogo || data.domainLogo || "";
|
||||
const icon = data.storeSideIcon || data.domainIcon || "";
|
||||
if (logo) {
|
||||
localStorage.setItem("sellerlogoImg", logo);
|
||||
storeSideLogo.value = logo;
|
||||
}
|
||||
if (icon) {
|
||||
localStorage.setItem("sellerIconImg", icon);
|
||||
applyFavicon(icon);
|
||||
}
|
||||
if (data.siteName) {
|
||||
localStorage.setItem("sellersiteName", data.siteName);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
userInfo.value = JSON.parse(Cookies.get("userInfoSeller"));
|
||||
checkTag(route.name);
|
||||
loadUnreadMessageCount();
|
||||
|
||||
const currWidth = document.body.clientWidth;
|
||||
if (currWidth <= 1200) {
|
||||
@@ -214,6 +291,7 @@ watch(
|
||||
}
|
||||
checkTag(name);
|
||||
util.title(currentPageTitle.value);
|
||||
loadUnreadMessageCount();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawer" title="页面配置" size="300px">
|
||||
<h3>内容设置</h3>
|
||||
<div class="config-item flex flex-a-c flex-j-sb">
|
||||
<div>
|
||||
<el-tooltip
|
||||
placement="bottom-end"
|
||||
content="关闭之后部分页面点击'查看''详情'等按钮将跳到新页面展示"
|
||||
>
|
||||
<div>多标签Tab页内嵌模式</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-switch v-model="setting.isUseTabsRouter" />
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useSettingStore } from "@/stores/setting";
|
||||
import { setStore } from "@/libs/storage";
|
||||
|
||||
defineOptions({ name: "configDrawer" });
|
||||
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
const drawer = ref(false);
|
||||
|
||||
const setting = computed(() => settingStore.setting);
|
||||
|
||||
watch(
|
||||
setting,
|
||||
(val) => {
|
||||
setStore("setting", val);
|
||||
settingStore.updateSetting(val);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
function open() {
|
||||
drawer.value = true;
|
||||
}
|
||||
|
||||
function close() {
|
||||
drawer.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open, close });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
* {
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 10px 0 20px 0;
|
||||
}
|
||||
|
||||
.config-item {
|
||||
cursor: pointer;
|
||||
margin-bottom: 20px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row class="header">
|
||||
<img alt="店铺 Logo" class="logo" :src="storeSideLogo" />
|
||||
<img alt="平台 Logo" class="logo" :src="storeSideLogo" />
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
@@ -16,7 +16,7 @@ function init() {
|
||||
getSite();
|
||||
}
|
||||
function applyFavicon(href) {
|
||||
if (!href) return;
|
||||
if (!href || href === "undefined" || href === "null") return;
|
||||
const link =
|
||||
document.querySelector("link[rel*='icon']") ||
|
||||
document.createElement("link");
|
||||
@@ -29,16 +29,18 @@ function getSite() {
|
||||
loadSiteSettings()
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
const logo = data.storeSideLogo || data.domainLogo || "";
|
||||
const icon = data.storeSideIcon || data.domainIcon || "";
|
||||
const expirationTime = new Date().setHours(new Date().getHours() + 1);
|
||||
localStorage.setItem("seller_expiration_time", expirationTime);
|
||||
localStorage.setItem("sellersiteName", data.siteName);
|
||||
localStorage.setItem("sellerlogoImg", data.storeSideLogo);
|
||||
localStorage.setItem("sellerIconImg", data.storeSideIcon);
|
||||
localStorage.setItem("sellersiteName", data.siteName || "");
|
||||
if (logo) localStorage.setItem("sellerlogoImg", logo);
|
||||
if (icon) localStorage.setItem("sellerIconImg", icon);
|
||||
localStorage.setItem("sellerCompanyName", data.companyName || "");
|
||||
localStorage.setItem("sellerCompanyUrl", data.companyUrl || "");
|
||||
storeSideLogo.value = data.storeSideLogo || storeSideLogo.value;
|
||||
storeSideLogo.value = logo || storeSideLogo.value;
|
||||
if (data.siteName) window.document.title = data.siteName;
|
||||
applyFavicon(data.storeSideIcon);
|
||||
applyFavicon(icon);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
<!--
|
||||
商家功能搜索:仅检索当前账号已授权且已注册的菜单,支持键盘选择。
|
||||
@author Bulbasaur
|
||||
@since 2026-11-08
|
||||
-->
|
||||
<template>
|
||||
<button type="button" class="menu-search-trigger" aria-label="搜索功能菜单" @click="openSearch">
|
||||
<el-icon :size="17"><Search /></el-icon><span>搜索功能菜单</span><kbd>/</kbd>
|
||||
</button>
|
||||
<el-dialog v-model="visible" class="seller-menu-search" title="搜索功能" width="560px" align-center
|
||||
@opened="focusInput" @closed="keyword = ''">
|
||||
<el-input ref="inputRef" v-model="keyword" placeholder="搜索菜单,例如:商品、订单、优惠券" size="large" clearable
|
||||
aria-label="搜索菜单" @keydown.down.prevent="moveSelection(1)" @keydown.up.prevent="moveSelection(-1)"
|
||||
@keydown.enter.prevent="navigate(results[selected])">
|
||||
<template #prefix><el-icon><Search /></el-icon></template>
|
||||
</el-input>
|
||||
<div class="search-summary">{{ keyword.trim() ? `找到 ${results.length} 个功能` : '全部可用功能' }}</div>
|
||||
<div ref="resultsRef" class="search-results">
|
||||
<button v-for="(item, index) in results" :key="`${item.topName}-${item.name}`" type="button"
|
||||
class="search-result" :class="{ selected: selected === index }" @click="navigate(item)" @mouseenter="selected = index">
|
||||
<div><strong>{{ item.title }}</strong><span>{{ item.topTitle }} / {{ item.groupTitle }}</span></div>
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</button>
|
||||
<el-empty v-if="!results.length" :image-size="72" description="没有匹配的功能,试试其他关键词" />
|
||||
</div>
|
||||
<template #footer><div class="search-help"><span>↑ ↓ 选择</span><span>Enter 打开</span><span>Esc 关闭</span></div></template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Search, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import { flattenNavigation, searchNavigation } from "@/libs/seller-navigation";
|
||||
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const visible = ref(false);
|
||||
const keyword = ref("");
|
||||
const selected = ref(0);
|
||||
const inputRef = ref(null);
|
||||
const resultsRef = ref(null);
|
||||
const items = computed(() => flattenNavigation(appStore.navigationMenus).filter((item) => router.hasRoute(item.name)));
|
||||
const results = computed(() => searchNavigation(items.value, keyword.value));
|
||||
|
||||
/** 每次打开清空上次关键词,避免残留搜索状态。 */
|
||||
function openSearch() { keyword.value = ""; selected.value = 0; visible.value = true; }
|
||||
/** 等弹层完成动画后聚焦输入框。 */
|
||||
function focusInput() { inputRef.value?.focus(); }
|
||||
/** 键盘移动候选项并滚动到可见区域;空列表不产生无效索引。 */
|
||||
async function moveSelection(step) {
|
||||
if (!results.value.length) return;
|
||||
selected.value = (selected.value + step + results.value.length) % results.value.length;
|
||||
await nextTick();
|
||||
resultsRef.value?.children[selected.value]?.scrollIntoView({ block: "nearest" });
|
||||
}
|
||||
/** 只允许打开当前权限搜索结果;清空关闭的弹层避免遮挡业务页面。 */
|
||||
function navigate(item) {
|
||||
if (!item || !items.value.some((entry) => entry.name === item.name)) return;
|
||||
visible.value = false;
|
||||
router.push({ name: item.name });
|
||||
}
|
||||
/** 仅在非编辑区域按 / 唤起搜索,不截获输入框、富文本和其他弹窗内的按键。 */
|
||||
function handleShortcut(event) {
|
||||
if (event.key !== "/" || event.ctrlKey || event.metaKey || event.altKey || visible.value ||
|
||||
event.target.closest?.('input, textarea, select, [contenteditable="true"], [role="dialog"]')) return;
|
||||
event.preventDefault();
|
||||
openSearch();
|
||||
}
|
||||
watch(results, () => { selected.value = 0; });
|
||||
watch(() => appStore.navigationMenus, () => { visible.value = false; keyword.value = ""; });
|
||||
onMounted(() => window.addEventListener("keydown", handleShortcut));
|
||||
onBeforeUnmount(() => window.removeEventListener("keydown", handleShortcut));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.menu-search-trigger { width: 240px; height: 34px; display: flex; align-items: center; gap: 9px; padding: 0 12px; border: 1px solid #eceef3; border-radius: 7px; background: #f7f8fb; color: #969cab; font: inherit; font-size: 12px; cursor: pointer;
|
||||
&:hover { border-color: #c5d2ff; color: #315efb; }
|
||||
&:focus-visible { outline: 2px solid #315efb; }
|
||||
kbd { margin-left: auto; padding: 0 5px; border: 1px solid #e0e4ed; border-radius: 3px; background: #fff; font-family: inherit; }
|
||||
}
|
||||
.search-summary { padding: 18px 2px 8px; font-size: 12px; color: #969cab; }
|
||||
.search-results { max-height: 380px; overflow-y: auto; }
|
||||
.search-result { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 12px; margin: 3px 0; border: 0; border-radius: 7px; background: #fff; text-align: left; cursor: pointer; color: #858c9c;
|
||||
strong { display: block; font-size: 14px; font-weight: 500; color: #303749; }
|
||||
span { display: block; margin-top: 5px; font-size: 12px; }
|
||||
&.selected, &:focus-visible { background: #eef2ff; strong { color: #315efb; } }
|
||||
}
|
||||
.search-help { display: flex; gap: 20px; color: #969cab; font-size: 12px; }
|
||||
@media (max-width: 1100px) { .menu-search-trigger { width: 180px; } }
|
||||
</style>
|
||||
@@ -78,7 +78,7 @@ watch([() => route.fullPath, () => appStore.navigationMenus], syncRouteMenu, { i
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 隐藏滚动条但保留滚轮、触控和键盘滚动,确保下方栏目仍可访问。
|
||||
.seller-navigation { height: calc(100% - 64px); box-sizing: border-box; padding: 18px 14px 32px; overflow-y: auto; overflow-x: hidden; scrollbar-width: none; background: #fff;
|
||||
.seller-navigation { height: 100%; box-sizing: border-box; padding: 18px 14px 32px; overflow-y: auto; overflow-x: hidden; scrollbar-width: none; background: #fff;
|
||||
&::-webkit-scrollbar { display: none; width: 0; height: 0; }
|
||||
}
|
||||
.nav-heading { width: 100%; display: flex; align-items: center; gap: 13px; min-height: 46px; padding: 11px 14px; border: 0; border-radius: 6px; background: transparent; color: #242832; text-align: left; font: inherit; font-size: 15px; font-weight: 600; cursor: pointer;
|
||||
|
||||
@@ -24,15 +24,15 @@
|
||||
}
|
||||
|
||||
.sidebar-menu-con {
|
||||
height: 100%;
|
||||
height: calc(100% - 60px);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
z-index: 21;
|
||||
width: 300px;
|
||||
transition: width 0.3s; // background: rgb(73, 80, 96)
|
||||
background: #fff;
|
||||
border-right: 1px solid #e9ecf2;
|
||||
border-right: 1px solid #e4e7ed;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@@ -53,12 +53,15 @@
|
||||
&-header-con {
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
display: block;
|
||||
padding-left: 300px;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
height: 106px;
|
||||
z-index: 20;
|
||||
border-bottom: 1px solid #e9ecf2;
|
||||
height: 60px;
|
||||
z-index: 22;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
box-shadow: none;
|
||||
transition: padding 0.3s;
|
||||
}
|
||||
@@ -125,10 +128,10 @@
|
||||
}
|
||||
|
||||
&-header {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 60px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e9ecf2;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
position: relative;
|
||||
z-index: 11;
|
||||
@@ -158,7 +161,7 @@
|
||||
|
||||
padding: 0 24px;
|
||||
gap: 20px;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
height: 100%;
|
||||
|
||||
|
||||
@@ -233,7 +236,7 @@
|
||||
position: absolute;
|
||||
left: 300px;
|
||||
right: 0;
|
||||
top: 106px;
|
||||
top: 60px;
|
||||
bottom: 0;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
@@ -262,19 +265,21 @@
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.logo-con {
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
.main .logo-con {
|
||||
flex: 0 0 300px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 12px 16px;
|
||||
padding: 8px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
justify-content: flex-start;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #e9ecf2;
|
||||
img {
|
||||
max-height: 36px;
|
||||
max-width: 48px;
|
||||
display: block;
|
||||
max-height: 44px;
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
@@ -296,6 +301,7 @@
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
|
||||
.nav-item {
|
||||
font-size: 14px;
|
||||
}
|
||||
@@ -334,8 +340,19 @@
|
||||
|
||||
// 导航与顶部栏的样式局限于商家外层布局,不覆盖业务页面的组件主题。
|
||||
.main {
|
||||
.brand-caption { color: #252b3a; font-size: 15px; font-weight: 600; white-space: nowrap; }
|
||||
.header-page-info { display: flex; align-items: center; gap: 12px; min-width: 0; font-size: 13px;
|
||||
.page-path-bar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 42px;
|
||||
padding: 8px 20px;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
}
|
||||
.header-page-info { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 13px;
|
||||
strong { color: #303749; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
}
|
||||
.workspace-label { color: #969cab; white-space: nowrap; }
|
||||
@@ -347,13 +364,20 @@
|
||||
&:hover { background: #f5f7fb; color: #315efb; }
|
||||
&:focus-visible { outline: 2px solid #315efb; }
|
||||
}
|
||||
.header-message-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
.single-page-con .single-page { margin: 16px; }
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.main {
|
||||
.header-avator-con { padding: 0 16px; gap: 12px; }
|
||||
.page-path-bar { padding: 8px 14px; }
|
||||
.user-dropdown-innercon { gap: 10px; }
|
||||
.workspace-label, .header-divider, .header-store-name { display: none; }
|
||||
.header-store-name { display: none; }
|
||||
.single-page-con .single-page { margin: 12px; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +84,12 @@ import { computed, onMounted, reactive, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { Bell, ChatDotRound, Clock, Delete } from "@element-plus/icons-vue";
|
||||
import * as API_Index from "@/api/index";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
|
||||
defineOptions({ name: "message_index" });
|
||||
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const loading = ref(true);
|
||||
const mesTypeList = ref([
|
||||
@@ -153,7 +155,10 @@ function refreshMessage() {
|
||||
}
|
||||
function refreshUnreadCount() {
|
||||
API_Index.getAllMessage(params).then((res) => {
|
||||
if (res.success) unReadCount.value = res.result.UN_READY.total;
|
||||
if (res.success) {
|
||||
unReadCount.value = res.result.UN_READY.total;
|
||||
appStore.setUnreadMessageCount(unReadCount.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
function getAll() {
|
||||
@@ -161,6 +166,7 @@ function getAll() {
|
||||
loading.value = false;
|
||||
if (res.success) {
|
||||
unReadCount.value = res.result.UN_READY.total;
|
||||
appStore.setUnreadMessageCount(unReadCount.value);
|
||||
currentMesList.value = res.result.UN_READY.records;
|
||||
}
|
||||
});
|
||||
|
||||
312
seller/src/views/shop/addressManage.vue
Normal file
312
seller/src/views/shop/addressManage.vue
Normal file
@@ -0,0 +1,312 @@
|
||||
<!--
|
||||
商家端地址管理页面:集中维护店铺发货地址与退货(售后)地址。
|
||||
@author Bulbasaur
|
||||
@since 2026-11-09
|
||||
-->
|
||||
<template>
|
||||
<el-card>
|
||||
<div class="setting-page">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
label-width="150px"
|
||||
label-position="right"
|
||||
:model="form"
|
||||
:rules="formRules"
|
||||
>
|
||||
<div class="setting-section">
|
||||
<div class="section-title">发货地址</div>
|
||||
<el-form-item label="发货人姓名" prop="salesConsignorName">
|
||||
<el-input
|
||||
v-model="form.salesConsignorName"
|
||||
maxlength="11"
|
||||
clearable
|
||||
placeholder="请输入发货人姓名"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="发货人手机号" prop="salesConsignorMobile">
|
||||
<el-input
|
||||
v-model="form.salesConsignorMobile"
|
||||
maxlength="11"
|
||||
clearable
|
||||
placeholder="请输入发货人手机号"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="地址" prop="salesConsignorAddressId">
|
||||
<span v-if="form.salesConsignorAddressPath" class="address-text">
|
||||
{{ form.salesConsignorAddressPath }}
|
||||
</span>
|
||||
<el-button @click="handleChangeAddress('addressGoods')">选择</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址" prop="salesConsignorDetail">
|
||||
<el-input
|
||||
v-model="form.salesConsignorDetail"
|
||||
clearable
|
||||
maxlength="50"
|
||||
placeholder="请输入详细地址"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="setting-section">
|
||||
<div class="section-title">退货地址</div>
|
||||
<el-form-item label="收货人" prop="salesConsigneeName">
|
||||
<el-input
|
||||
v-model="form.salesConsigneeName"
|
||||
maxlength="11"
|
||||
clearable
|
||||
placeholder="请输入收货人姓名"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="收货人电话" prop="salesConsigneeMobile">
|
||||
<el-input
|
||||
v-model="form.salesConsigneeMobile"
|
||||
maxlength="11"
|
||||
clearable
|
||||
placeholder="请输入收货人电话"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="售后地址" prop="salesConsigneeAddressId">
|
||||
<span v-if="form.salesConsigneeAddressPath" class="address-text">
|
||||
{{ form.salesConsigneeAddressPath }}
|
||||
</span>
|
||||
<el-button @click="handleChangeAddress('salesConsigneeAddressPath')">选择</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址" prop="salesConsigneeDetail">
|
||||
<el-input
|
||||
v-model="form.salesConsigneeDetail"
|
||||
clearable
|
||||
maxlength="50"
|
||||
placeholder="请输入详细地址"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="submit-bar">
|
||||
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<multipleMap ref="mapRef" @callback="callbackAddress" />
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import * as API_Shop from "@/api/shops";
|
||||
import multipleMap from "@/views/my-components/map/multiple-map";
|
||||
import * as RegExp from "@/libs/RegExp.js";
|
||||
import { Message } from "@/utils/message";
|
||||
|
||||
defineOptions({ name: "addressManage" });
|
||||
|
||||
const currentKey = ref("");
|
||||
const submitLoading = ref(false);
|
||||
|
||||
const form = ref({
|
||||
salesConsignorName: "",
|
||||
salesConsignorMobile: "",
|
||||
salesConsignorAddressId: "",
|
||||
salesConsignorAddressPath: "",
|
||||
salesConsignorDetail: "",
|
||||
salesConsigneeName: "",
|
||||
salesConsigneeMobile: "",
|
||||
salesConsigneeAddressId: "",
|
||||
salesConsigneeAddressPath: "",
|
||||
salesConsigneeDetail: "",
|
||||
});
|
||||
|
||||
const formRules = {
|
||||
salesConsignorName: [
|
||||
{ required: true, message: "请输入发货人姓名", trigger: "blur" },
|
||||
],
|
||||
salesConsignorMobile: [
|
||||
{ required: true, message: "手机号不能为空", trigger: "blur" },
|
||||
{
|
||||
pattern: RegExp.mobile,
|
||||
trigger: "blur",
|
||||
message: "请输入正确的手机号",
|
||||
},
|
||||
],
|
||||
salesConsignorDetail: [
|
||||
{ required: true, message: "请输入详细地址", trigger: "blur" },
|
||||
],
|
||||
salesConsigneeName: [
|
||||
{ required: true, message: "请输入收货人", trigger: "blur" },
|
||||
],
|
||||
salesConsigneeMobile: [
|
||||
{ required: true, message: "手机号不能为空", trigger: "blur" },
|
||||
{
|
||||
pattern: RegExp.mobile,
|
||||
trigger: "blur",
|
||||
message: "请输入正确的手机号",
|
||||
},
|
||||
],
|
||||
salesConsigneeDetail: [
|
||||
{ required: true, message: "请输入详细地址", trigger: "blur" },
|
||||
],
|
||||
};
|
||||
|
||||
const formRef = ref(null);
|
||||
const mapRef = ref(null);
|
||||
|
||||
/**
|
||||
* 接收地图/行政区选择器回传的地址数据。
|
||||
* @param {object} val 地址选择结果
|
||||
*/
|
||||
function callbackAddress(val) {
|
||||
if (val.type === "select") {
|
||||
const paths = val.data.map((item) => item.name).join(",");
|
||||
const ids = val.data.map((item) => item.id).join(",");
|
||||
|
||||
if (currentKey.value === "addressGoods") {
|
||||
form.value.salesConsignorAddressPath = paths;
|
||||
form.value.salesConsignorAddressId = ids;
|
||||
}
|
||||
if (currentKey.value === "salesConsigneeAddressPath") {
|
||||
form.value.salesConsigneeAddressPath = paths;
|
||||
form.value.salesConsigneeAddressId = ids;
|
||||
}
|
||||
} else {
|
||||
if (currentKey.value === "addressGoods") {
|
||||
form.value.salesConsignorAddressPath = val.data.addr;
|
||||
form.value.salesConsignorAddressId = val.data.addrId;
|
||||
}
|
||||
if (currentKey.value === "salesConsigneeAddressPath") {
|
||||
form.value.salesConsigneeAddressPath = val.data.addr;
|
||||
form.value.salesConsigneeAddressId = val.data.addrId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开地址选择弹窗。
|
||||
* @param {string} key 当前编辑的地址类型标识
|
||||
*/
|
||||
function handleChangeAddress(key) {
|
||||
currentKey.value = key;
|
||||
mapRef.value.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取店铺发货地址配置。
|
||||
*/
|
||||
function getDeliverAddress() {
|
||||
API_Shop.getDeliverAddress().then((res) => {
|
||||
if (res.success && res.result) {
|
||||
form.value.salesConsignorName = res.result.salesConsignorName || "";
|
||||
form.value.salesConsignorMobile = res.result.salesConsignorMobile || "";
|
||||
form.value.salesConsignorAddressId = res.result.salesConsignorAddressId || "";
|
||||
form.value.salesConsignorAddressPath = res.result.salesConsignorAddressPath || "";
|
||||
form.value.salesConsignorDetail = res.result.salesConsignorDetail || "";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取商家退货地址配置。
|
||||
*/
|
||||
function getRefundGoodsAddress() {
|
||||
API_Shop.getRefundGoodsAddress().then((res) => {
|
||||
if (res.success && res.result) {
|
||||
form.value.salesConsigneeName = res.result.salesConsigneeName || "";
|
||||
form.value.salesConsigneeMobile = res.result.salesConsigneeMobile || "";
|
||||
form.value.salesConsigneeAddressId = res.result.salesConsigneeAddressId || "";
|
||||
form.value.salesConsigneeAddressPath = res.result.salesConsigneeAddressPath || "";
|
||||
form.value.salesConsigneeDetail = res.result.salesConsigneeDetail || "";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一校验并保存发货地址与退货地址配置。
|
||||
*/
|
||||
function handleSubmit() {
|
||||
formRef.value.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
submitLoading.value = true;
|
||||
try {
|
||||
const deliverParams = {
|
||||
salesConsignorName: form.value.salesConsignorName,
|
||||
salesConsignorMobile: form.value.salesConsignorMobile,
|
||||
salesConsignorAddressId: form.value.salesConsignorAddressId,
|
||||
salesConsignorAddressPath: form.value.salesConsignorAddressPath,
|
||||
salesConsignorDetail: form.value.salesConsignorDetail,
|
||||
};
|
||||
const refundParams = {
|
||||
salesConsigneeName: form.value.salesConsigneeName,
|
||||
salesConsigneeMobile: form.value.salesConsigneeMobile,
|
||||
salesConsigneeAddressId: form.value.salesConsigneeAddressId,
|
||||
salesConsigneeAddressPath: form.value.salesConsigneeAddressPath,
|
||||
salesConsigneeDetail: form.value.salesConsigneeDetail,
|
||||
};
|
||||
const [deliverRes, refundRes] = await Promise.all([
|
||||
API_Shop.editDeliverAddress(deliverParams),
|
||||
API_Shop.saveRefundGoodsAddress(refundParams),
|
||||
]);
|
||||
if (deliverRes?.success && refundRes?.success) {
|
||||
Message.success("保存成功");
|
||||
init();
|
||||
}
|
||||
} finally {
|
||||
submitLoading.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
getDeliverAddress();
|
||||
getRefundGoodsAddress();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.setting-page {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.setting-section {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 20px 24px 4px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
margin-left: 0 !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.el-input) {
|
||||
width: 400px !important;
|
||||
}
|
||||
|
||||
.address-text {
|
||||
margin-right: 10px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.submit-bar {
|
||||
text-align: center;
|
||||
margin: 24px 0 8px;
|
||||
}
|
||||
</style>
|
||||
294
seller/src/views/shop/shopInfo.vue
Normal file
294
seller/src/views/shop/shopInfo.vue
Normal file
@@ -0,0 +1,294 @@
|
||||
<!--
|
||||
店铺信息页面:展示商家入驻时填写的企业及联系人信息、营业执照与法人信息、财务结算信息、店铺及经营信息。
|
||||
@author Bulbasaur
|
||||
@since 2026-11-09
|
||||
-->
|
||||
<template>
|
||||
<div class="shop-info-page">
|
||||
<el-card v-loading="loading" shadow="never" class="info-card">
|
||||
<div class="section-block">
|
||||
<div class="section-title">店铺及经营信息</div>
|
||||
<el-descriptions :column="2" border class="shop-desc">
|
||||
<el-descriptions-item label="店铺名称">
|
||||
{{ blankFilter(storeInfo.storeName) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="商家账号">
|
||||
{{ blankFilter(storeInfo.memberName) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺类型">
|
||||
{{ storeInfo.selfOperated == 1 || storeInfo.selfOperated === true ? "自营" : "非自营" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺状态">
|
||||
{{ storeStatusText(storeInfo.storeDisable) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="开店时间">
|
||||
{{ blankFilter(storeInfo.createTime) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺定位">
|
||||
{{ blankFilter(storeInfo.storeCenter) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺所在地">
|
||||
{{ blankFilter(storeInfo.storeAddressPath) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺详细地址">
|
||||
{{ blankFilter(storeInfo.storeAddressDetail) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺LOGO">
|
||||
<el-image
|
||||
v-if="isValid(storeInfo.storeLogo)"
|
||||
:src="storeInfo.storeLogo"
|
||||
:preview-src-list="[storeInfo.storeLogo]"
|
||||
fit="cover"
|
||||
preview-teleported
|
||||
class="cert-img"
|
||||
/>
|
||||
<span v-else>暂未上传</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺经营类目">
|
||||
{{ categories.length ? categories.map((item) => item.name).join("、") : "暂未配置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="店铺简介" :span="2">
|
||||
{{ blankFilter(storeInfo.storeDesc) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title">企业及联系人信息</div>
|
||||
<el-descriptions :column="2" border class="shop-desc">
|
||||
<el-descriptions-item label="公司名称">
|
||||
{{ blankFilter(storeInfo.companyName) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="公司电话">
|
||||
{{ blankFilter(storeInfo.companyPhone) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="公司所在地">
|
||||
{{ blankFilter(storeInfo.companyAddressPath) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="公司详细地址">
|
||||
{{ blankFilter(storeInfo.companyAddress) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="员工总数">
|
||||
{{ isValid(storeInfo.employeeNum) ? `${storeInfo.employeeNum} 人` : "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="注册资金">
|
||||
{{ isValid(storeInfo.registeredCapital) ? `${storeInfo.registeredCapital} 万元` : "-" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联系人姓名">
|
||||
{{ blankFilter(storeInfo.linkName) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="联系人电话">
|
||||
{{ blankFilter(storeInfo.linkPhone) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="电子邮箱" :span="2">
|
||||
{{ blankFilter(storeInfo.companyEmail) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title">营业执照与法人信息</div>
|
||||
<el-descriptions :column="2" border class="shop-desc">
|
||||
<el-descriptions-item label="营业执照号">
|
||||
{{ blankFilter(storeInfo.licenseNum) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="法人姓名">
|
||||
{{ blankFilter(storeInfo.legalName) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="法人证件号" :span="2">
|
||||
{{ blankFilter(storeInfo.legalId) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="法定经营范围" :span="2">
|
||||
{{ blankFilter(storeInfo.scope) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="营业执照电子版">
|
||||
<el-image
|
||||
v-if="isValid(storeInfo.licencePhoto)"
|
||||
:src="storeInfo.licencePhoto"
|
||||
:preview-src-list="[storeInfo.licencePhoto]"
|
||||
fit="cover"
|
||||
preview-teleported
|
||||
class="cert-img"
|
||||
/>
|
||||
<span v-else>暂未上传</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="法人证件电子版">
|
||||
<template v-if="legalPhotoList.length">
|
||||
<el-image
|
||||
v-for="(img, idx) in legalPhotoList"
|
||||
:key="idx"
|
||||
:src="img"
|
||||
:preview-src-list="legalPhotoList"
|
||||
:initial-index="idx"
|
||||
fit="cover"
|
||||
preview-teleported
|
||||
class="cert-img"
|
||||
/>
|
||||
</template>
|
||||
<span v-else>暂未上传</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="section-block">
|
||||
<div class="section-title">财务结算信息</div>
|
||||
<el-descriptions :column="2" border class="shop-desc">
|
||||
<el-descriptions-item label="银行开户名">
|
||||
{{ blankFilter(storeInfo.settlementBankAccountName) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="银行账号">
|
||||
{{ blankFilter(storeInfo.settlementBankAccountNum) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="开户银行支行名称">
|
||||
{{ blankFilter(storeInfo.settlementBankBranchName) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="支行联行号">
|
||||
{{ blankFilter(storeInfo.settlementBankJointName) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="结算日" :span="2">
|
||||
<span v-if="settlementCycles.length">每月 {{ settlementCycles.join("、") }} 日</span>
|
||||
<span v-else>-</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import * as API_Shop from "@/api/shops";
|
||||
import { getGoodsCategoryAll } from "@/api/goods";
|
||||
|
||||
defineOptions({ name: "shopInfo" });
|
||||
|
||||
const loading = ref(false);
|
||||
const storeInfo = ref({});
|
||||
const categories = ref([]);
|
||||
|
||||
const isValid = (v) => v !== null && v !== undefined && v !== "" && v !== "null";
|
||||
|
||||
function blankFilter(v) {
|
||||
return isValid(v) ? v : "-";
|
||||
}
|
||||
|
||||
function storeStatusText(status) {
|
||||
const map = {
|
||||
OPEN: "营业中",
|
||||
CLOSED: "已关闭",
|
||||
APPLY: "申请开店中",
|
||||
APPLYING: "待平台审核",
|
||||
REFUSED: "审核未通过",
|
||||
};
|
||||
return map[status] || status || "-";
|
||||
}
|
||||
|
||||
const legalPhotoList = computed(() => {
|
||||
if (!isValid(storeInfo.value.legalPhoto)) {
|
||||
return [];
|
||||
}
|
||||
if (Array.isArray(storeInfo.value.legalPhoto)) {
|
||||
return storeInfo.value.legalPhoto.filter(isValid);
|
||||
}
|
||||
return String(storeInfo.value.legalPhoto)
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.filter(isValid);
|
||||
});
|
||||
|
||||
const settlementCycles = computed(() => {
|
||||
if (!isValid(storeInfo.value.settlementCycle)) {
|
||||
return [];
|
||||
}
|
||||
return String(storeInfo.value.settlementCycle)
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
});
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const [baseRes, detailRes, catRes] = await Promise.allSettled([
|
||||
API_Shop.getShopInfo(),
|
||||
API_Shop.getShopEntryDetail(),
|
||||
getGoodsCategoryAll(),
|
||||
]);
|
||||
|
||||
const merged = {};
|
||||
if (baseRes.status === "fulfilled" && baseRes.value?.success && baseRes.value.result) {
|
||||
Object.assign(merged, baseRes.value.result);
|
||||
}
|
||||
if (detailRes.status === "fulfilled" && detailRes.value?.success && detailRes.value.result) {
|
||||
Object.assign(merged, detailRes.value.result);
|
||||
}
|
||||
storeInfo.value = merged;
|
||||
|
||||
if (catRes.status === "fulfilled" && catRes.value?.success && Array.isArray(catRes.value.result)) {
|
||||
categories.value = catRes.value.result;
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.shop-info-page {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.section-block + .section-block {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
border-radius: 2px;
|
||||
background: var(--el-color-primary);
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.shop-desc {
|
||||
:deep(.el-descriptions__label) {
|
||||
width: 160px;
|
||||
color: #606266;
|
||||
background: #fafbfc;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__content) {
|
||||
color: #303133;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__cell) {
|
||||
padding: 12px 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cert-img {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
margin: 0 10px 4px 0;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #ebeef5;
|
||||
cursor: pointer;
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<el-card style="margin-left: 10px">
|
||||
<el-tabs v-model="type" @tab-click="handleClickType">
|
||||
<el-tabs v-model="type">
|
||||
<el-tab-pane label="基本信息" name="INFO">
|
||||
<el-form ref="formRef" :model="form" label-width="100px" :rules="formValidate">
|
||||
<el-form-item label="店铺名称">
|
||||
@@ -34,85 +34,6 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="发货地址">
|
||||
<el-form ref="addressGoodsRef" :model="addressGoods" label-width="120px" :rules="addressGoodsValidate" class="shop-setting-form">
|
||||
<el-form-item label="发货人姓名" prop="salesConsignorName">
|
||||
<el-input v-model="addressGoods.salesConsignorName" maxlength="11" clearable style="width: 20%">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="发货人手机号" prop="salesConsignorMobile">
|
||||
<el-input v-model="addressGoods.salesConsignorMobile" maxlength="11" clearable style="width: 20%">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="地址" prop="salesConsignorAddressId">
|
||||
<span>{{ addressGoods.salesConsignorAddressPath }}</span>
|
||||
<el-button style="margin-left: 10px;" @click="handleChangeAddress('addressGoods')">选择</el-button>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="地址名称" prop="salesConsignorAddressPath">
|
||||
<el-input
|
||||
v-model="addressGoods.salesConsignorAddressPath"
|
||||
clearable
|
||||
style="width: 20%"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="详细地址" prop="salesConsignorDetail">
|
||||
<el-input v-model="addressGoods.salesConsignorDetail" clearable style="width: 20%">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-button @click="setAddressGoods" type="primary" style="margin-left: 8px">确认
|
||||
</el-button>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="退货地址" name="REFUND_GOODS_ADDRESS">
|
||||
<el-form ref="addressFormRef" :model="addressForm" label-width="100px" :rules="afterFormValidate">
|
||||
<el-form-item label="收货人" prop="salesConsigneeName">
|
||||
<el-input v-model="addressForm.salesConsigneeName" maxlength="11" clearable style="width: 20%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="收货人电话" prop="salesConsigneeMobile">
|
||||
<el-input v-model="addressForm.salesConsigneeMobile" maxlength="11" style="width: 20%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="售后地址">
|
||||
<span>{{ addressForm.salesConsigneeAddressPath }}</span>
|
||||
<el-button style="margin-left: 10px;" @click="handleChangeAddress('salesConsigneeAddressPath')">选择</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址" prop="salesConsigneeDetail">
|
||||
<el-input v-model="addressForm.salesConsigneeDetail" clearable style="width: 20%" maxlength="50" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button @click="afterHandleSubmit" :loading="submitLoading" type="primary" style="margin-right: 5px">修改
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<!-- Udesk 坐席功能 后续维护 -->
|
||||
<!-- <el-tab-pane label="客服设置" name="UDESK">
|
||||
<el-form
|
||||
ref="udeskForm"
|
||||
:model="udeskForm"
|
||||
label-width="100px"
|
||||
:rules="udeskFormValidate"
|
||||
>
|
||||
<el-form-item label="坐席id" prop="merchantEuid">
|
||||
<el-input
|
||||
v-model="udeskForm.merchantEuid"
|
||||
maxlength="30"
|
||||
clearable
|
||||
style="width: 20%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
@click="merchantSubmit"
|
||||
:loading="submitLoading"
|
||||
type="primary"
|
||||
style="margin-right: 5px"
|
||||
>修改
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane> -->
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
|
||||
@@ -126,53 +47,23 @@ import * as API_Shop from "@/api/shops";
|
||||
import { validateMobile } from "@/libs/validate";
|
||||
import uploadPicThumb from "@/views/my-components/lili/upload-pic-thumb";
|
||||
import multipleMap from "@/views/my-components/map/multiple-map";
|
||||
import * as RegExp from "@/libs/RegExp.js";
|
||||
import Cookies from "js-cookie";
|
||||
import { Message } from "@/utils/message";
|
||||
|
||||
defineOptions({ name: "shopSetting" });
|
||||
|
||||
const currentKey = ref(""); //存储当前点击地址的key
|
||||
const currentKey = ref(""); // 存储当前点击地址的key
|
||||
const type = ref("INFO");
|
||||
|
||||
const storeName = ref(""); //店铺名称
|
||||
const storeName = ref(""); // 店铺名称
|
||||
|
||||
const addressForm = ref({
|
||||
// 退货地址
|
||||
salesConsigneeName: "", // 收货人姓名
|
||||
salesConsigneeMobile: "", // 收货人电话
|
||||
salesConsigneeAddressId: "", // 售后地址id,逗号分割
|
||||
salesConsigneeAddressPath: "", // 售后地址,逗号分割
|
||||
salesConsigneeDetail: "", // 详细地址
|
||||
});
|
||||
//im form
|
||||
const udeskForm = ref({
|
||||
merchantEuid: "",
|
||||
});
|
||||
const afterFormValidate = {
|
||||
salesConsigneeMobile: [
|
||||
{ required: true, message: "手机号不能为空", trigger: "blur" },
|
||||
{
|
||||
pattern: RegExp.mobile,
|
||||
trigger: "blur",
|
||||
message: "请输入正确的手机号",
|
||||
},
|
||||
],
|
||||
salesConsigneeName: [
|
||||
{ required: true, message: "请输入收货人", trigger: "blur" },
|
||||
],
|
||||
salesConsigneeDetail: [
|
||||
{ required: true, message: "请输入详细地址", trigger: "blur" },
|
||||
],
|
||||
};
|
||||
const form = ref({
|
||||
// 添加或编辑表单对象初始化数据
|
||||
storeAddressPath: "", // 店铺地址中文
|
||||
storeCenter: "", // 经度 + 纬度
|
||||
longitude: "", //经度
|
||||
latitude: "", //纬度
|
||||
storeAddressDetail: "", //详细地址
|
||||
storeAddressIdPath: "", //地址
|
||||
longitude: "", // 经度
|
||||
latitude: "", // 纬度
|
||||
storeAddressDetail: "", // 详细地址
|
||||
storeAddressIdPath: "", // 地址
|
||||
storeDesc: "", // 店铺描述
|
||||
pageShow: false,
|
||||
selfPickFlag: false,
|
||||
@@ -220,134 +111,69 @@ const formValidate = {
|
||||
},
|
||||
],
|
||||
};
|
||||
const submitLoading = ref(false); // 添加或编辑提交状态
|
||||
//发货地址
|
||||
const addressGoods = ref({
|
||||
salesConsignorName: " ",
|
||||
salesConsignorMobile: " ",
|
||||
salesConsignorAddressId: " ",
|
||||
salesConsignorAddressPath: " ",
|
||||
salesConsignorDetail: " ",
|
||||
});
|
||||
|
||||
const addressGoodsValidate = {
|
||||
salesConsignorName: [
|
||||
{ required: true, message: "请输入发货人姓名", trigger: "blur" },
|
||||
],
|
||||
salesConsignorMobile: [
|
||||
{ required: true, message: "手机号不能为空", trigger: "blur" },
|
||||
{
|
||||
pattern: RegExp.mobile,
|
||||
trigger: "blur",
|
||||
message: "请输入正确的手机号",
|
||||
},
|
||||
],
|
||||
salesConsignorDetail: [
|
||||
{ required: true, message: "请输入详细地址", trigger: "blur" },
|
||||
],
|
||||
};
|
||||
const submitLoading = ref(false);
|
||||
|
||||
const formRef = ref(null);
|
||||
const addressGoodsRef = ref(null);
|
||||
const addressFormRef = ref(null);
|
||||
const mapRef = ref(null);
|
||||
|
||||
// 回调地址
|
||||
function callbackAddress(val) {
|
||||
if (val.type === 'select') {
|
||||
const paths = val.data.map(item => item.name).join(',')
|
||||
if (val.type === "select") {
|
||||
const paths = val.data.map((item) => item.name).join(",");
|
||||
const ids = val.data.map((item) => item.id).join(",");
|
||||
|
||||
const ids = val.data.map(item => item.id).join(',')
|
||||
|
||||
if (currentKey.value === 'storeAddress') {
|
||||
form.value.storeAddressPath = paths
|
||||
form.value.storeAddressIdPath = ids
|
||||
form.value.storeCenter = val.data[val.data.length - 1].center
|
||||
if (currentKey.value === "storeAddress") {
|
||||
form.value.storeAddressPath = paths;
|
||||
form.value.storeAddressIdPath = ids;
|
||||
form.value.storeCenter = val.data[val.data.length - 1].center;
|
||||
}
|
||||
if (currentKey.value === 'addressGoods') {
|
||||
addressGoods.value.salesConsignorAddressPath = paths
|
||||
addressGoods.value.salesConsignorAddressId = ids
|
||||
}
|
||||
if (currentKey.value === 'salesConsigneeAddressPath') {
|
||||
addressForm.value.salesConsigneeAddressPath = paths
|
||||
addressForm.value.salesConsigneeAddressId = ids
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
if (currentKey.value === 'storeAddressstoreAddress') {
|
||||
} else {
|
||||
if (
|
||||
currentKey.value === "storeAddress" ||
|
||||
currentKey.value === "storeAddressstoreAddress"
|
||||
) {
|
||||
form.value.storeAddressPath = val.data.addr;
|
||||
form.value.storeAddressIdPath = val.data.addrId;
|
||||
form.value.storeCenter = val.data.position.lng + "," + val.data.position.lat;
|
||||
}
|
||||
if (currentKey.value === 'addressGoods') {
|
||||
addressGoods.value.salesConsignorAddressPath = val.data.addr;
|
||||
addressGoods.value.salesConsignorAddressId = val.data.addrId;
|
||||
}
|
||||
if (currentKey.value === 'salesConsigneeAddressPath') {
|
||||
addressForm.value.salesConsigneeAddressPath = val.data.addr;
|
||||
addressForm.value.salesConsigneeAddressId = val.data.addrId;
|
||||
form.value.storeCenter =
|
||||
val.data.position.lng + "," + val.data.position.lat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修改地址
|
||||
function handleChangeAddress(key) {
|
||||
currentKey.value = key
|
||||
currentKey.value = key;
|
||||
mapRef.value.open();
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
function init() {
|
||||
getShopInfo();
|
||||
getDeliverAddress()
|
||||
}
|
||||
|
||||
|
||||
function setAddressGoods() {
|
||||
addressGoodsRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
API_Shop.editDeliverAddress(addressGoods.value).then(res => {
|
||||
if (res.success) {
|
||||
Message.success("修改成功")
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
//获取店铺信息
|
||||
// 获取店铺信息
|
||||
function getShopInfo() {
|
||||
API_Shop.getShopInfo().then((res) => {
|
||||
if (res.success) {
|
||||
form.value = res.result;
|
||||
|
||||
storeName.value = res.result.storeName;
|
||||
form.value.storeCenter = res.result.storeCenter;
|
||||
Cookies.set("userInfoSeller", JSON.stringify(res.result));
|
||||
if (res.result.merchantEuid) {
|
||||
//赋予坐席id
|
||||
udeskForm.value.merchantEuid = res.result.merchantEuid;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function pageShow(type) {
|
||||
form.value.pageShow = type
|
||||
}
|
||||
function changeSelfPickFlag(item) {
|
||||
if (item) {
|
||||
form.value.selfPickFlag = item
|
||||
}
|
||||
}
|
||||
function getDeliverAddress() {
|
||||
API_Shop.getDeliverAddress().then(res => {
|
||||
if (res.success) {
|
||||
if (res.result != '' && res.result != null) {
|
||||
addressGoods.value = res.result;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function pageShow(val) {
|
||||
form.value.pageShow = val;
|
||||
}
|
||||
|
||||
//提交保存
|
||||
function changeSelfPickFlag(item) {
|
||||
if (item) {
|
||||
form.value.selfPickFlag = item;
|
||||
}
|
||||
}
|
||||
|
||||
// 提交保存
|
||||
function handleSubmit() {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
@@ -363,42 +189,6 @@ function handleSubmit() {
|
||||
});
|
||||
}
|
||||
|
||||
//tab切换
|
||||
function handleClickType(pane) {
|
||||
const name = pane.paneName;
|
||||
//退款
|
||||
if (name === "INFO") {
|
||||
getShopInfo();
|
||||
}
|
||||
//退货
|
||||
if (name === "REFUND_GOODS_ADDRESS") {
|
||||
getRefundGoodsAddress();
|
||||
}
|
||||
}
|
||||
//获取商家退货地址
|
||||
function getRefundGoodsAddress() {
|
||||
API_Shop.getRefundGoodsAddress().then((res) => {
|
||||
if (res.result != null) {
|
||||
addressForm.value = res.result;
|
||||
}
|
||||
});
|
||||
}
|
||||
//提交保存
|
||||
function afterHandleSubmit() {
|
||||
addressFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
submitLoading.value = true;
|
||||
API_Shop.saveRefundGoodsAddress(addressForm.value).then((res) => {
|
||||
submitLoading.value = false;
|
||||
if (res.success) {
|
||||
Message.success("修改成功");
|
||||
getRefundGoodsAddress();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
@@ -408,15 +198,4 @@ onMounted(() => {
|
||||
margin-left: 10px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.shop-setting-form {
|
||||
:deep(.el-form-item) {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
white-space: nowrap;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user