feat: 添加ERP服务和系统服务,完善员工门户功能
## 新增服务模块 ### 1. ERP服务 (hzhub-erp) - 新增独立的ERP数据适配服务 - 支持SQL Server 2008 R2数据源 - 提供动态API配置管理系统 - 包含客户管理、销售数据等业务接口 ### 2. 系统服务 (hzhub-system) - 新增独立的系统管理服务 - 用户、角色、权限、部门、菜单管理 - 租户管理、操作日志、在线用户监控 - 工作流引擎(warm-flow)集成 - 企业微信审批同步功能 ### 3. API网关 (hzhub-gateway) - 新增Spring Cloud Gateway网关服务 - JWT认证、路由分发、限流熔断 - XSS防护、请求日志记录 - 统一入口端口8080 ## 后台管理功能增强 ### ERP动态API管理 - 新增动态API配置管理界面 - API测试、文档预览、统计监控 - 错误日志查看、缓存管理 - 从数据库表自动导入API配置 ### 系统管理增强 - 企业微信配置管理 - 企业微信审批同步配置 - 部门和用户管理优化 ## 员工门户功能完善 ### 业务页面 - 审批中心:工作流审批、待办任务 - CRM管理:客户关系管理 - 经销商管理:经销商数据展示 - 供应链管理:采购、库存、销售 - BI报表:数据可视化分析 - ERP数据探索:SQL Server数据查询 ### 个人中心 - 基本设置:个人信息管理 - 安全设置:密码修改、登录日志 - 锁屏功能:自动锁屏、手动锁屏 ### 其他功能 - 标签页管理:多标签页导航 - 页面缓存:keepAlive缓存机制 - 会话超时:自动检测并提示 ## 经销商门户 ### 页面路由 - 新增经销商管理页面路由 - AI聊天界面完善 ## 文档更新 - ERP API数据库初始化指南 - ERP API前端完整实现文档 - ERP API测试和验证指南 - Gateway路由迁移计划 - 项目配置文档更新 ## 部署脚本 - 统一启动/停止/重启脚本 - Docker Compose配置优化 - Nginx配置文件更新 ## 技术栈 - 后端: Spring Boot 3.5.8, Java 17 - 前端: Vue 3, TypeScript, Element Plus, Vben Admin - 工作流: warm-flow 1.8.2 - 网关: Spring Cloud Gateway - 数据库: MySQL 8.0, SQL Server 2008 R2 - 缓存: Redis 7 - 向量库: Weaviate 1.25.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
4
hzhub-portal-dealer/.env.development
Normal file
4
hzhub-portal-dealer/.env.development
Normal file
@@ -0,0 +1,4 @@
|
||||
# 开发环境配置
|
||||
VITE_API_URL=http://localhost:8080
|
||||
VITE_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
|
||||
VITE_WEB_TITLE=Dealer Portal 经销商门户
|
||||
@@ -25,7 +25,7 @@ server {
|
||||
|
||||
# API 代理 - 代理所有后端 API 请求
|
||||
# 匹配常见的后端 API 路径前缀
|
||||
location ~ ^/(system|chat|auth|resource|agent|knowledge|workflow)/ {
|
||||
location ~ ^/(system|chat|auth|resource|agent|knowledge|workflow|ai|erp)/ {
|
||||
proxy_pass ${UPSTREAM_URL};
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './auth';
|
||||
export * from './chat';
|
||||
export * from './erp';
|
||||
export * from './model';
|
||||
export * from './session';
|
||||
|
||||
@@ -28,22 +28,10 @@ const appList = ref([
|
||||
route: '/chat',
|
||||
},
|
||||
{
|
||||
id: 'ai-image',
|
||||
name: 'AI 画图',
|
||||
icon: 'Picture',
|
||||
route: '/ai-image',
|
||||
},
|
||||
{
|
||||
id: 'ai-video',
|
||||
name: 'AI 视频',
|
||||
icon: 'VideoCamera',
|
||||
route: '/ai-video',
|
||||
},
|
||||
{
|
||||
id: 'ai-ppt',
|
||||
name: 'AI PPT',
|
||||
icon: 'Document',
|
||||
route: '/ai-ppt',
|
||||
id: 'dealer',
|
||||
name: '经销商管理',
|
||||
icon: 'Shop',
|
||||
route: '/dealer',
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -54,8 +42,7 @@ const activeFooterBtn = ref<'agent' | 'knowledge' | null>(null);
|
||||
// 切换应用
|
||||
function handleAppClick(app: typeof appList.value[0]) {
|
||||
activeApp.value = app.id;
|
||||
// 这里可以添加路由跳转逻辑
|
||||
// router.push(app.route);
|
||||
router.push(app.route);
|
||||
}
|
||||
|
||||
// 智能体中心
|
||||
@@ -73,8 +60,12 @@ function handleKnowledgeBase() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 默认选中 AI 对话应用
|
||||
activeApp.value = 'ai-chat';
|
||||
// 根据当前路由设置激活的应用
|
||||
if (route.path.startsWith('/dealer')) {
|
||||
activeApp.value = 'dealer';
|
||||
} else {
|
||||
activeApp.value = 'ai-chat';
|
||||
}
|
||||
|
||||
// 获取会话列表
|
||||
console.log('[Aside.onMounted] 开始获取会话列表');
|
||||
@@ -91,6 +82,18 @@ onMounted(async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// 监听路由变化,更新激活的应用
|
||||
watch(
|
||||
() => route.path,
|
||||
(path) => {
|
||||
if (path.startsWith('/dealer')) {
|
||||
activeApp.value = 'dealer';
|
||||
} else {
|
||||
activeApp.value = 'ai-chat';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => sessionStore.currentSession,
|
||||
(newValue) => {
|
||||
|
||||
438
hzhub-portal-dealer/src/pages/dealer/index.vue
Normal file
438
hzhub-portal-dealer/src/pages/dealer/index.vue
Normal file
@@ -0,0 +1,438 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { getSalesAreas, getCustomerList, type CustomerVO } from '@/api/erp';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
// 选中的销区
|
||||
const selectedArea = ref<string>('');
|
||||
const salesAreas = ref<CustomerVO[]>([]);
|
||||
const loadingAreas = ref(false);
|
||||
|
||||
// 经销商列表
|
||||
const dealers = ref<CustomerVO[]>([]);
|
||||
const loadingDealers = ref(false);
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(20);
|
||||
const total = ref(0);
|
||||
|
||||
// 加载销区列表
|
||||
async function loadSalesAreas() {
|
||||
loadingAreas.value = true;
|
||||
try {
|
||||
const res = await getSalesAreas();
|
||||
// API 返回包装格式:{ code, msg, data }
|
||||
salesAreas.value = res?.data || [];
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.message || '加载销区列表失败');
|
||||
} finally {
|
||||
loadingAreas.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 加载经销商列表
|
||||
async function loadDealers() {
|
||||
if (!selectedArea.value) {
|
||||
dealers.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
loadingDealers.value = true;
|
||||
try {
|
||||
const res = await getCustomerList({
|
||||
pageNum: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
salesAreaCode: selectedArea.value,
|
||||
});
|
||||
dealers.value = res.rows || [];
|
||||
total.value = res.total || 0;
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.message || '加载经销商列表失败');
|
||||
} finally {
|
||||
loadingDealers.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 选择销区
|
||||
function handleAreaChange() {
|
||||
currentPage.value = 1;
|
||||
loadDealers();
|
||||
}
|
||||
|
||||
// 分页
|
||||
function handlePageChange(page: number) {
|
||||
currentPage.value = page;
|
||||
loadDealers();
|
||||
}
|
||||
|
||||
// Logo 渐变色
|
||||
const logoGradients = [
|
||||
'linear-gradient(135deg, #1d5af3, #3378fc)',
|
||||
'linear-gradient(135deg, #8b5cf6, #a78bfa)',
|
||||
'linear-gradient(135deg, #16a34a, #22c55e)',
|
||||
'linear-gradient(135deg, #d97706, #f59e0b)',
|
||||
'linear-gradient(135deg, #dc2626, #ef4444)',
|
||||
'linear-gradient(135deg, #0ea5e9, #38bdf8)',
|
||||
'linear-gradient(135deg, #e11d48, #f43f5e)',
|
||||
'linear-gradient(135deg, #64748b, #94a3b8)',
|
||||
];
|
||||
|
||||
function getLogoBg(item: CustomerVO) {
|
||||
const idx = item.customerCode.charCodeAt(item.customerCode.length - 1) % logoGradients.length;
|
||||
return logoGradients[idx];
|
||||
}
|
||||
|
||||
// 状态标签
|
||||
function getStatusInfo(item: CustomerVO) {
|
||||
if (item.isStop === 1) {
|
||||
return { type: 'danger' as const, text: '已停用' };
|
||||
}
|
||||
return { type: 'success' as const, text: '合作中' };
|
||||
}
|
||||
|
||||
// 手机号脱敏
|
||||
function maskPhone(phone: string) {
|
||||
if (!phone || phone.length < 7) return phone || '--';
|
||||
return phone.slice(0, 3) + '****' + phone.slice(-4);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadSalesAreas();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dealer-page">
|
||||
<!-- Header -->
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">经销商管理</h1>
|
||||
<p class="page-desc">选择销区查看经销商信息</p>
|
||||
</div>
|
||||
|
||||
<!-- Sales Area Selection -->
|
||||
<div class="area-selector">
|
||||
<div class="selector-label">选择销区:</div>
|
||||
<el-select
|
||||
v-model="selectedArea"
|
||||
placeholder="请选择销区"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 300px"
|
||||
:loading="loadingAreas"
|
||||
@change="handleAreaChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="area in salesAreas"
|
||||
:key="area.salesAreaCode"
|
||||
:label="`${area.salesAreaName} (${area.salesAreaCode})`"
|
||||
:value="area.salesAreaCode"
|
||||
/>
|
||||
</el-select>
|
||||
<div v-if="selectedArea" class="area-info">
|
||||
<el-tag type="success" effect="plain" round>
|
||||
已选销区:{{ salesAreas.find(a => a.salesAreaCode === selectedArea)?.salesAreaName }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dealer Cards -->
|
||||
<div v-if="selectedArea" class="dealer-section">
|
||||
<div class="section-header">
|
||||
<h3 class="section-title">经销商列表</h3>
|
||||
<span class="section-count">共 {{ total }} 家</span>
|
||||
</div>
|
||||
|
||||
<div class="dealer-grid" v-loading="loadingDealers">
|
||||
<div
|
||||
v-for="dealer in dealers"
|
||||
:key="dealer.customerCode"
|
||||
class="dealer-card"
|
||||
>
|
||||
<div class="card-header">
|
||||
<div class="dealer-logo" :style="{ background: getLogoBg(dealer) }">
|
||||
{{ dealer.customerName.charAt(0) }}
|
||||
</div>
|
||||
<div class="dealer-identity">
|
||||
<span class="dealer-name">{{ dealer.customerName }}</span>
|
||||
<span class="dealer-code">{{ dealer.customerCode }}</span>
|
||||
</div>
|
||||
<el-tag :type="getStatusInfo(dealer).type" size="small" effect="light" round>
|
||||
{{ getStatusInfo(dealer).text }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">销区</span>
|
||||
<span class="detail-value">{{ dealer.salesAreaName || '--' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">品牌</span>
|
||||
<span class="detail-value">{{ dealer.brandName || '--' }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">联系人</span>
|
||||
<span class="detail-value">{{ dealer.contactName || '--' }} · {{ maskPhone(dealer.phone) }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">地址</span>
|
||||
<span class="detail-value">{{ [dealer.province, dealer.city].filter(Boolean).join(' ') || '--' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="dealer-kpi">
|
||||
<div class="kpi-item">
|
||||
<span class="kpi-value">{{ dealer.sdOrgName || '--' }}</span>
|
||||
<span class="kpi-label">经销组织</span>
|
||||
</div>
|
||||
<div class="kpi-item">
|
||||
<span class="kpi-value">{{ dealer.pricePlanName || '--' }}</span>
|
||||
<span class="kpi-label">价格方案</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty state -->
|
||||
<div v-if="!loadingDealers && dealers.length === 0" class="empty-state">
|
||||
<el-empty description="该销区暂无经销商数据" />
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="pagination-bar" v-if="total > pageSize">
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:total="total"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty area hint -->
|
||||
<div v-if="!selectedArea" class="empty-area-hint">
|
||||
<el-empty description="请先选择销区查看经销商列表" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dealer-page {
|
||||
padding: 20px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
.page-desc {
|
||||
font-size: 14px;
|
||||
color: var(--color-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.area-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 32px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.selector-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.area-info {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.dealer-section {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.section-count {
|
||||
font-size: 13px;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.dealer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.dealer-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.dealer-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.dealer-card {
|
||||
background: #fff;
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-sm);
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.25s ease;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 18px 20px 14px;
|
||||
}
|
||||
|
||||
.dealer-logo {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dealer-identity {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.dealer-name {
|
||||
font-size: 15px;
|
||||
font-weight: 650;
|
||||
color: var(--color-text-primary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dealer-code {
|
||||
font-family: 'SF Mono', Menlo, monospace;
|
||||
font-size: 11.5px;
|
||||
color: var(--color-text-secondary);
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 13px;
|
||||
color: var(--color-text-primary);
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 60%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
margin-top: 14px;
|
||||
padding: 14px 20px;
|
||||
border-top: 1px solid #f5f3f0;
|
||||
}
|
||||
|
||||
.dealer-kpi {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.kpi-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.kpi-value {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-primary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kpi-label {
|
||||
font-size: 11px;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.pagination-bar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.empty-area-hint {
|
||||
padding: 60px 0;
|
||||
}
|
||||
</style>
|
||||
@@ -31,6 +31,16 @@ export const layoutRouter: RouteRecordRaw[] = [
|
||||
isDefaultChat: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/dealer',
|
||||
name: 'dealer',
|
||||
component: () => import('@/pages/dealer/index.vue'),
|
||||
meta: {
|
||||
title: '经销商管理',
|
||||
icon: 'Shop',
|
||||
isKeepAlive: '1',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
33
hzhub-portal-dealer/start.sh
Executable file
33
hzhub-portal-dealer/start.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
# hzhub-portal-dealer 启动脚本
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PID_FILE=".pid"
|
||||
LOG_FILE="logs/dev.log"
|
||||
|
||||
mkdir -p logs
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
echo "Service already running (PID: $PID)"
|
||||
exit 1
|
||||
else
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Starting hzhub-portal-dealer..."
|
||||
nohup pnpm dev > "$LOG_FILE" 2>&1 &
|
||||
PID=$!
|
||||
|
||||
sleep 2
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
echo "$PID" > "$PID_FILE"
|
||||
echo "hzhub-portal-dealer started (PID: $PID)"
|
||||
echo "Port: http://localhost:5138"
|
||||
else
|
||||
echo "Failed to start. Check logs: $LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
34
hzhub-portal-dealer/stop.sh
Executable file
34
hzhub-portal-dealer/stop.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
# hzhub-portal-dealer 停止脚本
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PID_FILE=".pid"
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
echo "Stopping hzhub-portal-dealer (PID: $PID)..."
|
||||
kill "$PID" 2>/dev/null
|
||||
sleep 2
|
||||
if ps -p "$PID" > /dev/null 2>&1; then
|
||||
echo "Force killing..."
|
||||
kill -9 "$PID" 2>/dev/null
|
||||
fi
|
||||
echo "hzhub-portal-dealer stopped."
|
||||
fi
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
|
||||
# Fallback: kill by port
|
||||
if ss -tlnp 2>/dev/null | grep -q ':5138 '; then
|
||||
echo "Port 5138 still in use, killing by port..."
|
||||
fuser -k 5138/tcp 2>/dev/null
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
if ! ss -tlnp 2>/dev/null | grep -q ':5138 '; then
|
||||
echo "hzhub-portal-dealer stopped."
|
||||
else
|
||||
echo "hzhub-portal-dealer may still be running on port 5138."
|
||||
fi
|
||||
7
hzhub-portal-dealer/types/components.d.ts
vendored
7
hzhub-portal-dealer/types/components.d.ts
vendored
@@ -23,7 +23,11 @@ declare module 'vue' {
|
||||
ElImage: typeof import('element-plus/es')['ElImage']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
FilesSelect: typeof import('./../src/components/FilesSelect/index.vue')['default']
|
||||
IconSelect: typeof import('./../src/components/IconSelect/index.vue')['default']
|
||||
@@ -38,4 +42,7 @@ declare module 'vue' {
|
||||
VerificationCode: typeof import('./../src/components/LoginDialog/components/FormLogin/VerificationCode.vue')['default']
|
||||
WelecomeText: typeof import('./../src/components/WelecomeText/index.vue')['default']
|
||||
}
|
||||
export interface GlobalDirectives {
|
||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||
}
|
||||
}
|
||||
|
||||
5
hzhub-portal-dealer/types/import_meta.d.ts
vendored
5
hzhub-portal-dealer/types/import_meta.d.ts
vendored
@@ -1,12 +1,9 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_WEB_TITLE: string;
|
||||
readonly VITE_WEB_TITLE_EN: string;
|
||||
readonly VITE_WEB_ENV: string;
|
||||
readonly VITE_WEB_BASE_API: string;
|
||||
readonly VITE_API_URL: string;
|
||||
readonly VITE_CLIENT_ID: string;
|
||||
readonly VITE_WEB_TITLE: string;
|
||||
}
|
||||
|
||||
declare interface ImportMeta {
|
||||
|
||||
@@ -29,6 +29,17 @@ export default defineConfig((cnf) => {
|
||||
headers: {
|
||||
'Cache-Control': 'no-store',
|
||||
},
|
||||
proxy: {
|
||||
'/api': {
|
||||
changeOrigin: true,
|
||||
target: 'http://127.0.0.1:8080',
|
||||
ws: true,
|
||||
},
|
||||
'/erp': {
|
||||
changeOrigin: true,
|
||||
target: 'http://127.0.0.1:8080',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user