diff --git a/apps/src/api/request.ts b/apps/src/api/request.ts
index 27e3cdb..5b1b17e 100644
--- a/apps/src/api/request.ts
+++ b/apps/src/api/request.ts
@@ -13,6 +13,7 @@ import { useAccessStore } from '@vben/stores';
import { message } from 'antdv-next';
+import { getDevApiBaseURL } from '#/config/dev-api-switch';
import { useAuthStore } from '#/store';
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
@@ -48,6 +49,10 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
// 请求头处理
client.addRequestInterceptor({
fulfilled: async (config) => {
+ const devBaseURL = getDevApiBaseURL(String(config.url ?? ''));
+ if (devBaseURL) {
+ config.baseURL = devBaseURL;
+ }
const accessStore = useAccessStore();
const accessToken = accessStore.accessToken;
if (accessToken) {
diff --git a/apps/src/components/dev-api-switch.vue b/apps/src/components/dev-api-switch.vue
new file mode 100644
index 0000000..ae4cd87
--- /dev/null
+++ b/apps/src/components/dev-api-switch.vue
@@ -0,0 +1,66 @@
+
+
+
+
+ API
+
+
+
+
+
diff --git a/apps/src/config/dev-api-switch.ts b/apps/src/config/dev-api-switch.ts
new file mode 100644
index 0000000..2d1907e
--- /dev/null
+++ b/apps/src/config/dev-api-switch.ts
@@ -0,0 +1,79 @@
+export const DEV_API_SWITCH_STORAGE_KEY = '__chatapp3_admin_dev_api_target__';
+
+export const DEV_API_TARGETS = {
+ internal: 'internal',
+ prod: 'prod',
+} as const;
+
+export type DevApiTarget =
+ (typeof DEV_API_TARGETS)[keyof typeof DEV_API_TARGETS];
+
+export const DEV_API_OPTIONS: Array<{
+ label: string;
+ value: DevApiTarget;
+}> = [
+ {
+ label: '内网 API',
+ value: DEV_API_TARGETS.internal,
+ },
+ {
+ label: '线上 API',
+ value: DEV_API_TARGETS.prod,
+ },
+];
+
+const DEV_API_PREFIX_MAP: Record = {
+ [DEV_API_TARGETS.internal]: '/__dev_api_internal__',
+ [DEV_API_TARGETS.prod]: '/__dev_api_prod__',
+};
+
+function canUseStorage() {
+ return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';
+}
+
+export function isDevApiSwitchEnabled() {
+ return import.meta.env.DEV;
+}
+
+export function normalizeDevApiTarget(value: null | string | undefined): DevApiTarget {
+ return value === DEV_API_TARGETS.prod
+ ? DEV_API_TARGETS.prod
+ : DEV_API_TARGETS.internal;
+}
+
+export function getStoredDevApiTarget(): DevApiTarget {
+ if (!isDevApiSwitchEnabled() || !canUseStorage()) {
+ return DEV_API_TARGETS.internal;
+ }
+ return normalizeDevApiTarget(
+ window.localStorage.getItem(DEV_API_SWITCH_STORAGE_KEY),
+ );
+}
+
+export function setStoredDevApiTarget(target: DevApiTarget) {
+ if (!isDevApiSwitchEnabled() || !canUseStorage()) {
+ return;
+ }
+ window.localStorage.setItem(
+ DEV_API_SWITCH_STORAGE_KEY,
+ normalizeDevApiTarget(target),
+ );
+}
+
+export function getDevApiTargetLabel(target: DevApiTarget) {
+ return (
+ DEV_API_OPTIONS.find((item) => item.value === target)?.label ||
+ '内网 API'
+ );
+}
+
+export function getDevApiBaseURL(url?: string) {
+ if (!isDevApiSwitchEnabled()) {
+ return null;
+ }
+ const normalizedUrl = String(url || '');
+ if (/^https?:\/\//.test(normalizedUrl)) {
+ return null;
+ }
+ return DEV_API_PREFIX_MAP[getStoredDevApiTarget()];
+}
diff --git a/apps/src/layouts/basic.vue b/apps/src/layouts/basic.vue
index 8ce249e..ae6f6bb 100644
--- a/apps/src/layouts/basic.vue
+++ b/apps/src/layouts/basic.vue
@@ -17,8 +17,10 @@ import { useAccessStore, useUserStore } from '@vben/stores';
import { $t } from '#/locales';
import { useAuthStore } from '#/store';
+import DevApiSwitch from '#/components/dev-api-switch.vue';
import LoginForm from '#/views/_core/authentication/login.vue';
+const isDev = import.meta.env.DEV;
const notifications = ref([
{
id: 1,
@@ -141,6 +143,9 @@ watch(
+
+
+
import('#/views/operate/ludo-game.vue'),
meta: { title: 'Ludo飞行棋' },
},
- {
- name: 'SetTop',
- path: 'set-top-room',
- component: () => import('#/views/operate/set-top-room.vue'),
- meta: { title: '置顶房间' },
- },
- {
- name: 'SetHot',
- path: 'set-hot-room',
- component: () => import('#/views/operate/set-hot-room.vue'),
- meta: { title: '热门房间' },
- },
{
name: 'RefundDeductTagLog',
path: 'refund-deduct-tag-log',
component: () => import('#/views/operate/refund-deduct-tag-log.vue'),
meta: { title: '退款扣除目标' },
},
- {
- name: 'PayCountry',
- path: 'pay/country',
- component: () => import('#/views/operate/pay-country.vue'),
- meta: { title: '开通支付国家' },
- },
- {
- name: 'RegionRelation',
- path: 'region/relation',
- component: () => import('#/views/operate/region-relation.vue'),
- meta: { title: '支付区域关系' },
- },
- {
- name: 'PayApplication',
- path: 'pay/application',
- component: () => import('#/views/operate/pay-application.vue'),
- meta: { title: '应用管理' },
- },
- {
- name: 'PayFactory',
- path: 'pay/factory',
- component: () => import('#/views/operate/pay-factory.vue'),
- meta: { title: '支付厂商' },
- },
- {
- name: 'PayChannel',
- path: 'pay/channel',
- component: () => import('#/views/operate/pay-channel.vue'),
- meta: { title: '支付渠道' },
- },
- {
- name: 'OpenPayCountry',
- path: 'open_pay/country',
- component: () => import('#/views/operate/pay-country.vue'),
- meta: { title: '开通支付国家' },
- },
{
name: 'OperateCnfLottery',
path: 'cnf/lottery',
component: () => import('#/views/operate/lottery-wheel-config.vue'),
meta: { title: '抽奖品配置' },
},
- {
- name: 'OperateBusinessDevelopment',
- path: 'room/business-development',
- component: () => import('#/views/operate/business-development.vue'),
- meta: { title: 'BD列表' },
- },
{
name: 'OperateAdministrator',
path: 'administrator',
@@ -215,30 +161,12 @@ const routes: RouteRecordRaw[] = [
component: () => import('#/views/operate/teen-patti.vue'),
meta: { title: '炸金花' },
},
- {
- name: 'OperateContributionBalance',
- path: 'contribution/balance',
- component: () => import('#/views/operate/contribution-balance.vue'),
- meta: { title: '房间贡献余额' },
- },
{
name: 'OperatePush',
path: 'push',
component: () => import('#/views/operate/push.vue'),
meta: { title: '消息推送' },
},
- {
- name: 'OperateOnlineRoom',
- path: 'online/room',
- component: () => import('#/views/operate/online-room.vue'),
- meta: { title: '在线房间' },
- },
- {
- name: 'OperateRoomProfile',
- path: 'profile/room',
- component: () => import('#/views/operate/room-profile.vue'),
- meta: { title: '房间资料信息' },
- },
{
name: 'OperateSysCountry',
path: 'sys/country',
@@ -293,12 +221,6 @@ const routes: RouteRecordRaw[] = [
component: () => import('#/views/operate/game-egg.vue'),
meta: { title: '砸金蛋' },
},
- {
- name: 'ActivityRoomContribution',
- path: '/activity/room/contribution',
- component: () => import('#/views/operate/room-contribution.vue'),
- meta: { title: '房间支持活动' },
- },
{
name: 'ActivityHallFame',
path: '/activity/hall-fame',
diff --git a/apps/src/router/routes/modules/payment.ts b/apps/src/router/routes/modules/payment.ts
new file mode 100644
index 0000000..43517bc
--- /dev/null
+++ b/apps/src/router/routes/modules/payment.ts
@@ -0,0 +1,53 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+const routes: RouteRecordRaw[] = [
+ {
+ meta: {
+ icon: 'lucide:credit-card',
+ order: 50.1,
+ title: '支付管理',
+ },
+ name: 'PaymentManager',
+ path: '/payment/manager',
+ redirect: '/payment/manager/country',
+ children: [
+ {
+ name: 'PayCountry',
+ path: 'country',
+ alias: '/operate/manager/pay/country',
+ component: () => import('#/views/operate/pay-country.vue'),
+ meta: { title: '开通支付国家' },
+ },
+ {
+ name: 'RegionRelation',
+ path: 'region/relation',
+ alias: '/operate/manager/region/relation',
+ component: () => import('#/views/operate/region-relation.vue'),
+ meta: { title: '支付区域关系' },
+ },
+ {
+ name: 'PayApplication',
+ path: 'application',
+ alias: '/operate/manager/pay/application',
+ component: () => import('#/views/operate/pay-application.vue'),
+ meta: { title: '应用管理' },
+ },
+ {
+ name: 'PayFactory',
+ path: 'factory',
+ alias: '/operate/manager/pay/factory',
+ component: () => import('#/views/operate/pay-factory.vue'),
+ meta: { title: '支付厂商' },
+ },
+ {
+ name: 'PayChannel',
+ path: 'channel',
+ alias: '/operate/manager/pay/channel',
+ component: () => import('#/views/operate/pay-channel.vue'),
+ meta: { title: '支付渠道' },
+ },
+ ],
+ },
+];
+
+export default routes;
diff --git a/apps/src/router/routes/modules/room.ts b/apps/src/router/routes/modules/room.ts
new file mode 100644
index 0000000..83fd539
--- /dev/null
+++ b/apps/src/router/routes/modules/room.ts
@@ -0,0 +1,67 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+const routes: RouteRecordRaw[] = [
+ {
+ meta: {
+ icon: 'lucide:house',
+ order: 50.2,
+ title: '房间管理',
+ },
+ name: 'RoomManager',
+ path: '/room/manager',
+ redirect: '/room/manager/set-top-room',
+ children: [
+ {
+ name: 'SetTop',
+ path: 'set-top-room',
+ alias: '/operate/manager/set-top-room',
+ component: () => import('#/views/operate/set-top-room.vue'),
+ meta: { title: '置顶房间' },
+ },
+ {
+ name: 'SetHot',
+ path: 'set-hot-room',
+ alias: '/operate/manager/set-hot-room',
+ component: () => import('#/views/operate/set-hot-room.vue'),
+ meta: { title: '热门房间' },
+ },
+ {
+ name: 'OperateBusinessDevelopment',
+ path: 'business-development',
+ alias: '/operate/manager/room/business-development',
+ component: () => import('#/views/operate/business-development.vue'),
+ meta: { title: 'BD列表' },
+ },
+ {
+ name: 'OperateContributionBalance',
+ path: 'contribution/balance',
+ alias: '/operate/manager/contribution/balance',
+ component: () => import('#/views/operate/contribution-balance.vue'),
+ meta: { title: '房间贡献余额' },
+ },
+ {
+ name: 'OperateOnlineRoom',
+ path: 'online/room',
+ alias: '/operate/manager/online/room',
+ component: () => import('#/views/operate/online-room.vue'),
+ meta: { title: '在线房间' },
+ },
+ {
+ name: 'OperateRoomProfile',
+ path: 'profile/room',
+ alias: '/operate/manager/profile/room',
+ component: () => import('#/views/operate/room-profile.vue'),
+ meta: { title: '房间资料信息' },
+ },
+ {
+ name: 'ActivityRoomContribution',
+ path: 'activity/room/contribution',
+ alias: '/activity/room/contribution',
+ component: () => import('#/views/operate/room-contribution.vue'),
+ meta: { title: '房间支持活动' },
+ },
+ ],
+ },
+];
+
+export default routes;
diff --git a/apps/src/views/approval/components/edit-user-drawer.vue b/apps/src/views/approval/components/edit-user-drawer.vue
index 4635b2f..5fe7994 100644
--- a/apps/src/views/approval/components/edit-user-drawer.vue
+++ b/apps/src/views/approval/components/edit-user-drawer.vue
@@ -14,11 +14,12 @@ import {
FormItem,
Input,
Select,
- SelectOption,
Space,
message,
} from 'antdv-next';
+import TeamCountrySelect from '#/views/team/components/team-country-select.vue';
+
const props = defineProps<{
open: boolean;
userId: number | string;
@@ -31,26 +32,58 @@ const emit = defineEmits<{
const loading = ref(false);
const birthday = ref('');
-const form = reactive>({
- bornDay: '',
- bornMonth: '',
- bornYear: '',
- countryName: '',
- id: '',
- userNickname: '',
- userSex: undefined,
-});
+
+const genderOptions = [
+ { label: '女', value: 0 },
+ { label: '男', value: 1 },
+];
+
+function createForm() {
+ return {
+ bornDay: '',
+ bornMonth: '',
+ bornYear: '',
+ countryCode: '',
+ countryId: '',
+ countryName: '',
+ id: '',
+ userNickname: '',
+ userSex: undefined as number | undefined,
+ };
+}
+
+const form = reactive>(createForm());
+
+function normalizeUserSex(value: number | string | undefined) {
+ if (value === '' || value === null || value === undefined) {
+ return undefined;
+ }
+ const nextValue = Number(value);
+ return Number.isNaN(nextValue) ? undefined : nextValue;
+}
+
+function handleCountryChange(
+ _value: number | string,
+ row: Record | null,
+) {
+ form.countryId = row?.id || '';
+ form.countryCode = row?.alphaTwo || row?.alphaThree || '';
+ form.countryName = row?.aliasName || row?.countryName || '';
+}
watch(
() => [props.open, props.userId],
async ([open, userId]) => {
if (!open || !userId) {
+ Object.assign(form, createForm());
+ birthday.value = '';
return;
}
loading.value = true;
try {
const data = await getUserBaseInfo(String(userId));
- Object.assign(form, data || {});
+ Object.assign(form, createForm(), data || {});
+ form.userSex = normalizeUserSex(data?.userSex);
birthday.value =
data?.bornYear && data?.bornMonth && data?.bornDay
? `${String(data.bornYear)}-${String(data.bornMonth).padStart(2, '0')}-${String(data.bornDay).padStart(2, '0')}`
@@ -120,10 +153,13 @@ async function handleSubmit() {
-
+
-
+
diff --git a/apps/src/views/team/components/bd-lead-form-modal.vue b/apps/src/views/team/components/bd-lead-form-modal.vue
index b9c75ff..530b35d 100644
--- a/apps/src/views/team/components/bd-lead-form-modal.vue
+++ b/apps/src/views/team/components/bd-lead-form-modal.vue
@@ -6,14 +6,12 @@ import {
updateBdLead,
} from '#/api/legacy/team';
import AccountInput from '#/components/account-input.vue';
-import { regionConfigTable } from '#/api/legacy/system';
+import SystemRegionSelect from '#/views/operate/components/system-region-select.vue';
import {
Form,
FormItem,
Modal,
- Select,
- SelectOption,
Input,
message,
} from 'antdv-next';
@@ -30,8 +28,6 @@ const emit = defineEmits<{
}>();
const saving = ref(false);
-const regionLoading = ref(false);
-const regionOptions = ref>>([]);
const form = reactive({
contact: '',
@@ -52,28 +48,13 @@ watch(
}
form.id = String(props.row?.id || '');
form.userId = String(props.row?.userId || props.row?.userProfile?.id || '');
- form.sysOrigin = props.sysOrigin || props.row?.sysOrigin || 'LIKEI';
+ form.sysOrigin = props.row?.sysOrigin || props.sysOrigin || 'LIKEI';
form.contact = props.row?.contact || '';
form.regionId = String(props.row?.regionId || '');
- await loadRegions(form.sysOrigin);
},
{ immediate: true },
);
-async function loadRegions(sysOrigin: string) {
- if (!sysOrigin) {
- regionOptions.value = [];
- return;
- }
- regionLoading.value = true;
- try {
- const result = await regionConfigTable({ sysOrigin });
- regionOptions.value = result || [];
- } finally {
- regionLoading.value = false;
- }
-}
-
async function handleSubmit() {
if (!isUpdate.value && !String(form.userId || '').trim()) {
message.warning('请输入BD Leader 用户ID');
@@ -124,20 +105,11 @@ async function handleSubmit() {
/>
-
+ :sys-origin="form.sysOrigin"
+ />
diff --git a/apps/vite.config.ts b/apps/vite.config.ts
index 07a06a9..1c35a05 100644
--- a/apps/vite.config.ts
+++ b/apps/vite.config.ts
@@ -1,11 +1,43 @@
import { defineConfig } from '@vben/vite-config';
+const DEV_CONSOLE_PREFIX = '/console';
+const DEV_API_INTERNAL_PREFIX = '/__dev_api_internal__';
+const DEV_API_PROD_PREFIX = '/__dev_api_prod__';
+const DEV_INTERNAL_CONSOLE_TARGET = 'http://127.0.0.1:2700';
+const DEV_INTERNAL_GOLANG_TARGET = 'http://127.0.0.1:2900';
+const DEV_PROD_TARGET = 'https://yumi-admin.haiyihy.com';
+
+function createPrefixRegExp(prefix: string) {
+ return new RegExp(`^${prefix.replaceAll('/', '\\/')}`);
+}
+
export default defineConfig(async () => {
return {
application: {},
vite: {
server: {
proxy: {
+ [`${DEV_API_INTERNAL_PREFIX}/go`]: {
+ changeOrigin: true,
+ rewrite: (path) =>
+ path.replace(createPrefixRegExp(`${DEV_API_INTERNAL_PREFIX}/go`), ''),
+ target: DEV_INTERNAL_GOLANG_TARGET,
+ ws: true,
+ },
+ [DEV_API_INTERNAL_PREFIX]: {
+ changeOrigin: true,
+ rewrite: (path) =>
+ path.replace(createPrefixRegExp(DEV_API_INTERNAL_PREFIX), DEV_CONSOLE_PREFIX),
+ target: DEV_INTERNAL_CONSOLE_TARGET,
+ ws: true,
+ },
+ [DEV_API_PROD_PREFIX]: {
+ changeOrigin: true,
+ rewrite: (path) =>
+ path.replace(createPrefixRegExp(DEV_API_PROD_PREFIX), DEV_CONSOLE_PREFIX),
+ target: DEV_PROD_TARGET,
+ ws: true,
+ },
'/console/go': {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/console\/go/, ''),