Commit e16169d0 by DaiJiezhang

Refine project configuration and phone dialog

- Update .gitignore rules

- Optimize phone-add-dialog component

- Refine API clients for phone and wechat modules

- Update start/stop batch scripts
parent 65b834c9
...@@ -13,3 +13,14 @@ localhost ...@@ -13,3 +13,14 @@ localhost
wechat-page.png wechat-page.png
backend/src/main/resources/application.yml backend/src/main/resources/application.yml
start-backend.bat start-backend.bat
# Local JDK setup, IDE-generated repository notes, and test artifacts.
.qoder/
jdk17/
test-artifacts/
temurin17.msi
temurin17.zip
_fix_phone_image_cell.py
_sync_files.py
_write_phone_image_cell.py
start-backend-jdk17.bat
backend/.mvn/jvm.config
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<title>学有为资产管理台</title> <title>学有为资产管理台</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%230f766e'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-size='26' font-family='Arial' fill='white'%3EXY%3C/text%3E%3C/svg%3E" /> <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%230f766e'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-size='26' font-family='Arial' fill='white'%3EXY%3C/text%3E%3C/svg%3E" />
<link rel="stylesheet" href="node_modules/element-plus/dist/index.css" /> <link rel="stylesheet" href="node_modules/element-plus/dist/index.css" />
<link rel="stylesheet" href="styles-v2.css?v=20260708c" /> <link rel="stylesheet" href="styles-v2.css?v=20260720-fix-list" />
</head> </head>
<body> <body>
......
...@@ -336,20 +336,19 @@ ...@@ -336,20 +336,19 @@
}; };
}, },
template: ` template: `
<el-dialog v-model="visible" width="860px" top="6vh" custom-class="phone-form-dialog"> <el-dialog v-model="visible" width="860px" align-center modal-class="phone-form-dialog-modal">
<template #header> <template #header>
<div class="phone-form-dialog__title"> <div class="phone-form-dialog__title">
<span class="phone-form-dialog__title-text">{{ isEdit ? '编辑手机号卡' : '新增手机号卡' }}</span> <span class="phone-form-dialog__title-text">{{ isEdit ? '编辑手机号卡' : '新增手机号卡' }}</span>
<span class="phone-form-dialog__title-hint">基础信息为必填,其余可按需补充</span> <span class="phone-form-dialog__title-hint">基础信息为必填,其余可按需补充</span>
</div> </div>
</template> </template>
<el-form :model="formData" :rules="rules" ref="formRef" label-width="120px" label-position="right" class="phone-form-dialog__form"> <el-form :model="formData" :rules="rules" ref="formRef" label-width="104px" label-position="right" class="phone-form-dialog__form">
<!-- 01 图片附件区域 --> <!-- 01 图片附件区域 -->
<div class="phone-form-dialog__section phone-form-dialog__section--image"> <div class="phone-form-dialog__section phone-form-dialog__section--image">
<div class="phone-form-dialog__section-title"> <div class="phone-form-dialog__section-title">
<span class="phone-form-dialog__section-no">01</span> <span class="phone-form-dialog__section-no">01</span>
<span class="phone-form-dialog__section-name">图片附件</span> <span class="phone-form-dialog__section-name">图片附件</span>
<span class="phone-form-dialog__section-sub">最多 2 张</span>
</div> </div>
<input ref="imageInputRef" type="file" accept="image/*" multiple style="display: none;" @change="handleImageFileChange" /> <input ref="imageInputRef" type="file" accept="image/*" multiple style="display: none;" @change="handleImageFileChange" />
<div class="phone-form-dialog__image-slots"> <div class="phone-form-dialog__image-slots">
...@@ -368,9 +367,8 @@ ...@@ -368,9 +367,8 @@
</div> </div>
</div> </div>
<div v-else class="phone-form-dialog__image-empty"> <div v-else class="phone-form-dialog__image-empty">
<div class="phone-form-dialog__image-empty-text">拖拽上传</div> <span class="phone-form-dialog__upload-icon" aria-hidden="true">⇧</span>
<div class="phone-form-dialog__image-empty-divider">/</div> <span class="phone-form-dialog__image-empty-text">拖拽上传 / 点击选择</span>
<div class="phone-form-dialog__image-empty-text">点击选择</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -420,12 +418,24 @@ ...@@ -420,12 +418,24 @@
<el-row :gutter="32"> <el-row :gutter="32">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="所在城市" prop="city"> <el-form-item label="所在城市" prop="city">
<el-input v-model="formData.city" placeholder="请输入号码归属地"></el-input> <el-input v-model="formData.city" placeholder="请输入城市"></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="卡使用地点" prop="cardUsageLocation"> <el-form-item label="卡使用地点" prop="cardUsageLocation">
<el-input v-model="formData.cardUsageLocation" placeholder="请输入当前使用地点"></el-input> <el-input v-model="formData.cardUsageLocation" placeholder="请输入使用地点"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="32">
<el-col :span="12">
<el-form-item label="抖音账号" prop="douyinAccount">
<el-input v-model="formData.douyinAccount" placeholder="请输入关联的抖音号"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="微信账号" prop="linkedWecom">
<el-input v-model="formData.linkedWecom" placeholder="请输入关联的微信号"></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
...@@ -440,74 +450,19 @@ ...@@ -440,74 +450,19 @@
<span class="phone-form-dialog__section-no">03</span> <span class="phone-form-dialog__section-no">03</span>
<span class="phone-form-dialog__section-name">辅助配置</span> <span class="phone-form-dialog__section-name">辅助配置</span>
</div> </div>
<el-row :gutter="32"> <div class="phone-form-dialog__settings-list">
<el-col :span="12"> <div class="phone-form-dialog__setting-row"><span class="phone-form-dialog__setting-name">号卡状态</span><div class="phone-form-dialog__switch"><span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.numberStatus }">{{ formData.numberStatus ? '正常' : '注销' }}</span><el-switch v-model="formData.numberStatus"></el-switch></div></div>
<el-form-item label="号卡状态" prop="cardStatus"> <div class="phone-form-dialog__setting-row"><span class="phone-form-dialog__setting-name">可变更 5 元套餐</span><div class="phone-form-dialog__switch"><span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.packageChange5yuan }">{{ formData.packageChange5yuan ? '可变更' : '不可变更' }}</span><el-switch v-model="formData.packageChange5yuan"></el-switch></div></div>
<el-select v-model="formData.cardStatus" style="width: 100%;"> <div class="phone-form-dialog__setting-row"><span class="phone-form-dialog__setting-name">开通微信</span><div class="phone-form-dialog__switch"><span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.wechat }">{{ formData.wechat ? '已开通' : '未开通' }}</span><el-switch v-model="formData.wechat"></el-switch></div></div>
<el-option label="正常" value="正常"></el-option> <div class="phone-form-dialog__setting-row"><span class="phone-form-dialog__setting-name">开通企业微信</span><div class="phone-form-dialog__switch"><span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.wecom }">{{ formData.wecom ? '已开通' : '未开通' }}</span><el-switch v-model="formData.wecom"></el-switch></div></div>
<el-option label="异常停机" value="异常停机"></el-option> <div class="phone-form-dialog__setting-row"><span class="phone-form-dialog__setting-name">可外呼</span><div class="phone-form-dialog__switch"><span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.outboundCall }">{{ formData.outboundCall ? '支持' : '不支持' }}</span><el-switch v-model="formData.outboundCall"></el-switch></div></div>
<el-option label="保号中" value="保号中"></el-option> <div class="phone-form-dialog__setting-row"><span class="phone-form-dialog__setting-name">小程序备案</span><div class="phone-form-dialog__switch"><span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.miniProgramFiling }">{{ formData.miniProgramFiling ? '已备案' : '未备案' }}</span><el-switch v-model="formData.miniProgramFiling"></el-switch></div></div>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="可变更 5 元套餐" prop="packageChange5yuan">
<div class="phone-form-dialog__switch">
<el-switch v-model="formData.packageChange5yuan"></el-switch>
<span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.packageChange5yuan }">{{ formData.packageChange5yuan ? '可变更' : '不可变更' }}</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="32">
<el-col :span="12">
<el-form-item label="开通微信" prop="wechat">
<div class="phone-form-dialog__switch">
<el-switch v-model="formData.wechat"></el-switch>
<span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.wechat }">{{ formData.wechat ? '已开通' : '未开通' }}</span>
</div> </div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开通企业微信" prop="wecom">
<div class="phone-form-dialog__switch">
<el-switch v-model="formData.wecom"></el-switch>
<span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.wecom }">{{ formData.wecom ? '已开通' : '未开通' }}</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="32">
<el-col :span="12">
<el-form-item label="可外呼" prop="outboundCall">
<div class="phone-form-dialog__switch">
<el-switch v-model="formData.outboundCall"></el-switch>
<span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.outboundCall }">{{ formData.outboundCall ? '支持' : '不支持' }}</span>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="小程序备案" prop="miniProgramFiling">
<div class="phone-form-dialog__switch">
<el-switch v-model="formData.miniProgramFiling"></el-switch>
<span class="phone-form-dialog__switch-status" :class="{ 'is-on': formData.miniProgramFiling }">{{ formData.miniProgramFiling ? '已备案' : '未备案' }}</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="32">
<el-col :span="24">
<el-form-item label="抖音账号" prop="douyinAccount">
<el-input v-model="formData.douyinAccount" placeholder="关联的抖音号"></el-input>
</el-form-item>
</el-col>
</el-row>
</div> </div>
</el-form> </el-form> <template #footer>
<template #footer>
<div class="phone-form-dialog__footer"> <div class="phone-form-dialog__footer">
<el-button @click="close">取消</el-button> <el-button @click="close">取消</el-button>
<el-button type="primary" class="phone-form-dialog__submit-btn" @click="handleSubmit">提交保存</el-button> <el-button type="primary" class="phone-form-dialog__submit-btn" @click="handleSubmit">提交</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
......
/**
* 代码作用(白话):把手机号接口能力挂载到页面共用对象,并统一使用本地后端 8888 端口;关联文件:F:/Project/xyw_console/src/modules/shared/wechat-api-client.js、F:/Project/xyw_console/start.bat;关联逻辑(调用链/消息链/数据流):页面模块 -> window.PhoneApiClient -> http://localhost:8888/api/wx-phones -> Spring Boot 后端。
*/
(function attachPhoneApiClient() { (function attachPhoneApiClient() {
const BASE_URL = 'http://localhost:8080/api/wx-phones'; const BASE_URL = 'http://localhost:8888/api/wx-phones';
/** /**
* 代码作用(白话):统一处理手机号接口返回,遇到后端报错时直接抛出明确错误,避免列表和弹窗各自重复判断;关联文件:F:/Project/xyw_console/app-v2.js、F:/Project/xyw_console/src/modules/phone/phone-list-runtime.js、F:/Project/xyw_console/src/modules/phone/phone-add-dialog.js;关联逻辑(调用链/消息链/数据流):listPhones()/savePhone()/deletePhone() -> parseJsonResponse() -> app-v2.js/手机号模块错误提示。 * 代码作用(白话):统一处理手机号接口返回,遇到后端报错时直接抛出明确错误,避免列表和弹窗各自重复判断;关联文件:F:/Project/xyw_console/app-v2.js、F:/Project/xyw_console/src/modules/phone/phone-list-runtime.js、F:/Project/xyw_console/src/modules/phone/phone-add-dialog.js;关联逻辑(调用链/消息链/数据流):listPhones()/savePhone()/deletePhone() -> parseJsonResponse() -> app-v2.js/手机号模块错误提示。
......
(function attachWechatApiClient() { /**
* 代码作用(白话):把企微接口能力挂载到页面共用对象,并统一使用本地后端 8888 端口;关联文件:F:/Project/xyw_console/src/modules/shared/phone-api-client.js、F:/Project/xyw_console/start.bat;关联逻辑(调用链/消息链/数据流):企微页面 -> window.WechatApiClient -> http://localhost:8888/api/wechat-records -> Spring Boot 后端。
*/
(function attachWechatApiClient() {
// 当前企微资料接口对应测试数据库;后续切换到生产数据库(正式业务库)时,需要同步改成生产环境对应的后端配置。 // 当前企微资料接口对应测试数据库;后续切换到生产数据库(正式业务库)时,需要同步改成生产环境对应的后端配置。
const BASE_URL = 'http://localhost:8080/api/wechat-records'; const BASE_URL = 'http://localhost:8888/api/wechat-records';
/** /**
* 代码作用(白话):统一解析企微接口返回,保证前端只认 code/message/data 这一套结构;关联文件:F:/Project/xyw_console/app-v2.js、F:/Project/xyw_console/src/modules/wechat/wechat-add-dialog.js、F:/Project/xyw_console/src/modules/wechat/wechat-list-runtime.js;关联逻辑(调用链/消息链/数据流):listWechatRecords()/getWechatRecord()/saveWechatRecord() -> parseJsonResponse() -> 页面列表/弹窗提示。 * 代码作用(白话):统一解析企微接口返回,保证前端只认 code/message/data 这一套结构;关联文件:F:/Project/xyw_console/app-v2.js、F:/Project/xyw_console/src/modules/wechat/wechat-add-dialog.js、F:/Project/xyw_console/src/modules/wechat/wechat-list-runtime.js;关联逻辑(调用链/消息链/数据流):listWechatRecords()/getWechatRecord()/saveWechatRecord() -> parseJsonResponse() -> 页面列表/弹窗提示。
......
...@@ -3,9 +3,11 @@ chcp 65001 >nul ...@@ -3,9 +3,11 @@ chcp 65001 >nul
set FRONTEND_PORT=8000 set FRONTEND_PORT=8000
set FRONTEND_URL=http://localhost:%FRONTEND_PORT% set FRONTEND_URL=http://localhost:%FRONTEND_PORT%
set BACKEND_URL=http://localhost:8080 REM Backend API requests use port 8888, matching backend/src/main/resources/application.yml.
set BACKEND_URL=http://localhost:8888
set FRONTEND_SCRIPT=%~dp0start-frontend.bat set FRONTEND_SCRIPT=%~dp0start-frontend.bat
set BACKEND_SCRIPT=%~dp0start-backend.bat REM Use the JDK 17 launcher so one-click startup does not call the legacy JDK path.
set BACKEND_SCRIPT=%~dp0start-backend-jdk17.bat
echo =================================================== echo ===================================================
echo [Starting Project] echo [Starting Project]
......
...@@ -3,7 +3,8 @@ setlocal EnableExtensions EnableDelayedExpansion ...@@ -3,7 +3,8 @@ setlocal EnableExtensions EnableDelayedExpansion
chcp 65001 >nul chcp 65001 >nul
set "FRONTEND_PORT=8000" set "FRONTEND_PORT=8000"
set "BACKEND_PORT=8080" REM Keep this port aligned with backend/src/main/resources/application.yml and start-backend-jdk17.bat.
set "BACKEND_PORT=8888"
echo =================================================== echo ===================================================
echo [Stopping Project] echo [Stopping Project]
...@@ -21,8 +22,8 @@ exit /b ...@@ -21,8 +22,8 @@ exit /b
:stopByPort :stopByPort
REM Purpose: collect every listening PID on the target port and stop them one by one. REM Purpose: collect every listening PID on the target port and stop them one by one.
REM Related files: start-frontend.bat, start-backend.bat. REM Related files: start-frontend.bat, start-backend-jdk17.bat.
REM Related flow: stop.bat -> stopByPort -> killProcess -> release port 8000 or 8080. REM Related flow: stop.bat -> stopByPort -> killProcess -> release port 8000 or 8888.
set "TARGET_PORT=%~1" set "TARGET_PORT=%~1"
set "TARGET_NAME=%~2" set "TARGET_NAME=%~2"
set "FOUND_ANY=0" set "FOUND_ANY=0"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment