| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453 |
- # API 接口文档
- ## 文档说明
- 本文档记录项目所有的 API 接口信息,包括请求方式、参数说明、响应格式等。所有接口遵循 RESTful 设计规范。
- ### 基础信息
- - **基础路径**: `/api`
- - **响应格式**: JSON
- - **字符编码**: UTF-8
- - **权限认证**: Sa-Token + JWT
- - **版本**: v1.0
- ### 🔐 请求头规范(强制性)
- **所有需要认证的接口必须在请求头中包含 Token,格式如下:**
- ```json
- {
- "Content-Type": "application/json;charset=utf-8",
- "Authorization": "Bearer {access_token}",
- "clientid": "e5cd7e4891bf95d1d19206ce24a7b32e",
- "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
- "referer": "http://localhost/login?redirect=%252Findex"
- }
- ```
- **请求头字段说明**:
- - **Authorization**: `Bearer ` + Token 值(⚠️ 注意 Bearer 后面有一个空格)
- - **clientid**: 客户端 ID,用于权限验证
- - **Content-Type**: 请求内容类型,必须为 application/json;charset=utf-8
- - **Accept-Language**: 语言设置,用于国际化
- - **referer**: 来源页面,用于安全验证
- **Token 格式强制要求**:
- - ✅ 正确:`"Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."`
- - ❌ 错误:`"Authorization": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."`(缺少 Bearer 前缀)
- - ❌ 错误:`"Authorization": "Bearer eyJ0eXAi..."`(Bearer 后面没有空格)
- ### 🔴 统一响应格式(强制性)
- **⚠️ 所有 API 接口必须严格遵循以下统一响应格式!**
- #### 📊 基础响应格式
- **分页列表响应格式**:
- ```json
- {
- "total": 7,
- "rows": [],
- "code": 200,
- "msg": "查询成功"
- }
- ```
- #### 🎯 详细响应格式说明
- **1. 分页列表响应**
- ```json
- {
- "total": 100,
- "rows": [
- {
- "id": 1,
- "name": "示例数据1",
- "createTime": "2025-06-30 12:00:00"
- },
- {
- "id": 2,
- "name": "示例数据2",
- "createTime": "2025-06-30 12:01:00"
- }
- ],
- "code": 200,
- "msg": "查询成功"
- }
- ```
- **2. 非分页列表响应**
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": [
- {
- "id": 1,
- "name": "示例数据1"
- },
- {
- "id": 2,
- "name": "示例数据2"
- }
- ]
- }
- ```
- **3. 单条数据响应**
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": {
- "id": 1,
- "name": "示例数据",
- "createTime": "2025-06-30 12:00:00"
- }
- }
- ```
- **4. 操作成功响应(无数据)**
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": null
- }
- ```
- **5. 错误响应**
- ```json
- {
- "code": 400,
- "msg": "参数错误:用户名不能为空",
- "data": null
- }
- ```
- #### 📋 状态码规范
- **成功状态码**:
- - `200` - 操作成功
- - `201` - 创建成功
- **客户端错误(4xx)**:
- - `400` - 请求参数错误
- - `401` - 未认证/认证失败
- - `403` - 无权限访问
- - `404` - 资源不存在
- - `409` - 数据冲突
- **服务端错误(5xx)**:
- - `500` - 服务器内部错误
- - `502` - 网关错误
- - `503` - 服务不可用
- #### 🚨 开发强制要求
- 1. **请求头必须包含 Bearer Token 格式的 Authorization**
- 2. **分页接口必须直接返回 TableDataInfo 格式(total、rows、code、msg)**
- 3. **非分页接口必须使用 R 类型包装返回结果**
- 4. **单条数据接口必须使用 R 类型包装返回结果**
- 5. **操作类接口必须使用 R 类型包装返回结果**
- 6. **必须包含 clientid、Content-Type 等必要请求头**
- #### 💥 违规检查
- 如发现接口不符合统一格式,必须立即修改!
- ---
- ## 0. 认证与登录 API
- ### 0.1 用户认证
- #### 用户登录
- **接口地址**: `POST /auth/login`
- **接口描述**: 用户登录认证接口,支持密码登录。请求数据使用 AES+RSA 混合加密传输,确保安全性。
- **权限要求**: 无需认证(公开接口)
- **安全机制**:
- - **数据加密**: 请求参数使用 AES 对称加密
- - **密钥保护**: AES 密钥使用 RSA 非对称加密
- - **自动解密**: 后端自动解密请求数据和响应数据
- **请求头配置**:
- ```json
- {
- "Content-Type": "application/json;charset=utf-8",
- "clientid": "e5cd7e4891bf95d1d19206ce24a7b32e",
- "encrypt-key": "[RSA加密的AES密钥]",
- "referer": "http://localhost/login?redirect=%252Findex",
- "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
- "isToken": "false",
- "isEncrypt": "true",
- "repeatSubmit": "false"
- }
- ```
- **关键请求头说明**:
- | 请求头名 | 必填 | 说明 | 示例值 |
- | ----------- | ---- | --------------------------------- | -------------------------------------------- |
- | clientid | 是 | 客户端 ID,用于身份验证 | "e5cd7e4891bf95d1d19206ce24a7b32e" |
- | encrypt-key | 是 | RSA 加密的 AES 密钥,用于数据解密 | "Q8Td0si9R3EYj3pFe50rzn/8wxo69Y9uR6LE..." |
- | referer | 是 | 来源页面地址,用于请求来源验证 | "http://localhost/login?redirect=%252Findex" |
- **加密流程说明**:
- 1. 前端生成随机 AES 密钥(32 位字符串)
- 2. 使用 AES-ECB-PKCS7 模式加密请求数据
- 3. 使用 RSA 公钥加密 AES 密钥
- 4. 将加密后的 AES 密钥放入请求头 `encrypt-key`
- 5. 后端使用 RSA 私钥解密 AES 密钥,再解密请求数据
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- | --------- | ------ | ---- | ------------------------------------ | ---------------------------------- |
- | tenantId | string | 是 | 租户 ID,多租户系统标识 | "000000" |
- | username | string | 是 | 用户名,长度 2-30 字符 | "admin" |
- | password | string | 是 | 用户密码,长度 5-30 字符 | "admin123" |
- | clientId | string | 是 | 客户端 ID,用于权限控制 | "e5cd7e4891bf95d1d19206ce24a7b32e" |
- | grantType | string | 是 | 授权类型,目前支持 password | "password" |
- | code | string | 否 | 验证码(当系统开启验证码时必填) | "1234" |
- | uuid | string | 否 | 验证码唯一标识(当需要验证码时必填) | "uuid-string" |
- **请求示例**:
- ```json
- {
- "tenantId": "000000",
- "username": "admin",
- "password": "admin123",
- "clientId": "e5cd7e4891bf95d1d19206ce24a7b32e",
- "grantType": "password"
- }
- ```
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": {
- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJ5MlhvbHRnd1Y2YjUzRnRMVzF4SFR1anRSUERjeGdmYyIsImNsaWVudGlkIjoiZTVjZDdlNDg5MWJmOTVkMWQxOTIwNmNlMjRhN2IzMmUiLCJ0ZW5hbnRJZCI6IjAwMDAwMCIsInVzZXJJZCI6MSwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MTAzLCJkZXB0TmFtZSI6IuaZuuiDveaOp-WItuWtpumZoiIsImRlcHRDYXRlZ29yeSI6IiIsIm5pY2tOYW1lIjoi55av54uC55qE54uu5a2QTGkifQ.WI6iY3AgwPz7ceI8WDsVy-GaTXZnU-JKUYUTjhQdoKM",
- "refresh_token": null,
- "expire_in": 604800,
- "refresh_expire_in": null,
- "client_id": "e5cd7e4891bf95d1d19206ce24a7b32e",
- "scope": null,
- "openid": null
- }
- }
- ```
- **实际 Token 解析信息**:
- | 字段名 | 值 | 说明 |
- | --------- | ----------------- | --------- |
- | userId | 1 | 用户 ID |
- | userName | admin | 用户名 |
- | nickName | 疯狂狮子 Li | 用户昵称 |
- | deptId | 103 | 部门 ID |
- | deptName | 智胜技术开发团队 | 部门名称 |
- | tenantId | 000000 | 租户 ID |
- | clientId | e5cd7e4891bf95... | 客户端 ID |
- | loginType | login | 登录类型 |
- **Token 有效期**: 7 天 (604800 秒)
- **响应参数说明**:
- | 参数名 | 类型 | 说明 |
- | ----------------- | ------ | ------------------------------ |
- | access_token | string | 访问令牌,用于 API 调用认证 |
- | refresh_token | string | 刷新令牌,用于获取新的访问令牌 |
- | expire_in | long | 访问令牌过期时间(秒) |
- | refresh_expire_in | long | 刷新令牌过期时间(秒) |
- | client_id | string | 客户端 ID |
- | scope | string | 权限范围 |
- | openid | string | 第三方登录标识(可为空) |
- **多种登录方式支持**:
- 系统采用策略模式,支持多种登录方式:
- 1. **密码登录** (`grantType: "password"`)
- - 使用用户名和密码登录
- - 支持验证码验证(可配置开关)
- - BCrypt 密码加密存储
- 2. **邮箱登录** (`grantType: "email"`)
- - 使用邮箱和邮箱验证码登录
- - 需要先发送邮箱验证码
- 3. **短信登录** (`grantType: "sms"`)
- - 使用手机号和短信验证码登录
- - 需要先发送短信验证码
- 4. **小程序登录** (`grantType: "xcx"`)
- - 微信小程序授权登录
- - 需要小程序码和应用 ID
- **错误码说明**:
- | 错误码 | 错误信息 | 说明 | 解决方案 |
- | ------ | ---------------------------- | ----------------------- | ---------------------- |
- | 400 | 参数校验失败 | 请求参数格式错误 | 检查参数格式和必填字段 |
- | 400 | 客户端 id 异常 | clientId 不存在或被禁用 | 检查 clientId 配置 |
- | 400 | 授权类型不正确 | grantType 不支持 | 使用支持的授权类型 |
- | 400 | 当前系统没有开启注册功能 | 租户未开启注册 | 联系管理员开启注册功能 |
- | 401 | 用户不存在 | 用户名不存在 | 检查用户名是否正确 |
- | 401 | 用户已被停用 | 用户账号被禁用 | 联系管理员激活账号 |
- | 401 | 密码错误 | 用户密码不正确 | 检查密码是否正确 |
- | 401 | 验证码已过期 | 验证码超时 | 重新获取验证码 |
- | 401 | 验证码错误 | 验证码输入错误 | 检查验证码是否正确 |
- | 403 | 登录失败次数过多,账户已锁定 | 密码错误次数超限 | 等待解锁或联系管理员 |
- | 500 | 租户不存在 | tenantId 无效 | 检查租户配置 |
- **安全特性**:
- 1. **密码安全**:
- - BCrypt 哈希加密存储
- - 登录失败次数限制
- - 账户自动锁定机制
- 2. **传输安全**:
- - AES+RSA 混合加密
- - 防重放攻击保护
- - HTTPS 协议传输
- 3. **会话安全**:
- - JWT Token 认证
- - Token 自动过期机制
- - 刷新 Token 机制
- 4. **多租户安全**:
- - 租户隔离验证
- - 客户端权限控制
- - 不同设备类型支持
- **实际使用示例**:
- ```javascript
- // 完整的登录实现示例(AES+RSA加密)
- const axios = require('axios');
- const CryptoJS = require('crypto-js');
- const NodeRSA = require('node-rsa');
- async function loginWithEncryption(username = 'admin', password = 'admin123') {
- // 配置信息
- const CONFIG = {
- url: 'http://localhost/dev-api/auth/login',
- clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e',
- tenantId: '000000',
- referer: 'http://localhost/login?redirect=%252Findex',
- rsaKey: 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==',
- };
- // 生成32位随机AES密钥
- function generateAESKey() {
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let result = '';
- for (let i = 0; i < 32; i++) {
- result += chars.charAt(Math.floor(Math.random() * chars.length));
- }
- return result;
- }
- // AES加密
- function aesEncrypt(data, key) {
- const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
- return CryptoJS.AES.encrypt(data, keyUtf8, {
- mode: CryptoJS.mode.ECB,
- padding: CryptoJS.pad.Pkcs7,
- }).toString();
- }
- // RSA加密AES密钥
- function rsaEncrypt(aesKey) {
- const pemKey = `-----BEGIN PUBLIC KEY-----\n${CONFIG.rsaKey}\n-----END PUBLIC KEY-----`;
- const rsaKey = new NodeRSA(pemKey);
- rsaKey.setOptions({ encryptionScheme: 'pkcs1' });
- const aesKeyBase64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(aesKey));
- return rsaKey.encrypt(aesKeyBase64, 'base64');
- }
- // 生成AES密钥并加密登录数据
- const aesKey = generateAESKey();
- const loginData = {
- tenantId: CONFIG.tenantId,
- username: username,
- password: password,
- clientId: CONFIG.clientId,
- grantType: 'password',
- };
- const encryptedData = aesEncrypt(JSON.stringify(loginData), aesKey);
- const encryptedKey = rsaEncrypt(aesKey);
- // 设置请求头
- const headers = {
- 'Content-Type': 'application/json;charset=utf-8',
- clientid: CONFIG.clientId,
- 'encrypt-key': encryptedKey,
- referer: CONFIG.referer,
- 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
- isToken: 'false',
- isEncrypt: 'true',
- repeatSubmit: 'false',
- };
- // 发送登录请求
- const response = await axios.post(CONFIG.url, encryptedData, {
- headers: headers,
- timeout: 10000,
- });
- if (response.data.code === 200 && response.data.data?.access_token) {
- return response.data.data.access_token;
- } else {
- throw new Error(response.data.msg || 'Login failed');
- }
- }
- // 使用示例
- loginWithEncryption()
- .then((token) => {
- console.log('Login successful, token:', token);
- })
- .catch((error) => {
- console.error('Login failed:', error.message);
- });
- ```
- **快速测试脚本**:
- 项目中提供了完整的测试脚本,位于 `test/` 目录:
- - `test/custom-login-script.js` - 完整功能版
- - `test/quick-token-getter.js` - 快速获取版
- - `test/登录脚本使用说明.md` - 详细使用文档
- #### 退出登录
- **接口地址**: `POST /auth/logout`
- **接口描述**: 用户退出登录,清除服务端会话信息
- **权限要求**: 需要登录
- **请求参数**: 无需请求体
- **请求头**:
- ```json
- {
- "Authorization": "Bearer {access_token}"
- }
- ```
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "退出成功",
- "data": null
- }
- ```
- **功能说明**:
- - 清除服务端 Token 会话
- - 关闭 SSE 连接(如果开启)
- - 清理用户登录状态
- #### 获取验证码
- **接口地址**: `GET /auth/code`
- **接口描述**: 获取图形验证码,用于登录时的安全验证
- **权限要求**: 无需认证
- **请求参数**: 无
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": {
- "uuid": "d7c2c4c4-4e9d-4a5f-9c1a-2b3c4d5e6f7g",
- "img": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABH..."
- }
- }
- ```
- **响应参数说明**:
- | 参数名 | 类型 | 说明 |
- | ------ | ------ | ----------------------- |
- | uuid | string | 验证码唯一标识 |
- | img | string | Base64 编码的验证码图片 |
- **使用流程**:
- 1. 前端调用此接口获取验证码图片和 UUID
- 2. 用户输入验证码
- 3. 登录时将验证码和 UUID 一起提交
- 4. 服务端验证验证码的正确性和有效性
- ### 0.2 用户信息
- #### 获取当前用户信息
- **接口地址**: `GET /system/user/getInfo`
- **接口描述**: 获取当前登录用户的详细信息,包括角色权限等
- **权限要求**: 需要登录
- **请求参数**: 无
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": {
- "user": {
- "userId": 1,
- "userName": "admin",
- "nickName": "疯狂狮子Li",
- "email": "admin@example.com",
- "phonenumber": "13800138000",
- "sex": "1",
- "avatar": "/profile/avatar/default.jpg",
- "status": "0",
- "loginIp": "127.0.0.1",
- "loginDate": "2025-01-26 10:30:00",
- "tenantId": "000000",
- "deptId": 103,
- "deptName": "智胜技术开发团队"
- },
- "roles": ["admin", "common"],
- "permissions": ["*:*:*"]
- }
- }
- ```
- **超级管理员权限说明**:
- admin 用户具有系统最高权限 `*:*:*`,可以访问所有功能模块和执行所有操作。
- ### 0.3 租户管理
- #### 获取租户列表
- **接口地址**: `GET /auth/tenant/list`
- **接口描述**: 获取系统可用的租户列表,用于登录时选择租户
- **权限要求**: 无需认证
- **请求参数**: 无
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": {
- "tenantEnabled": true,
- "voList": [
- {
- "tenantId": "000000",
- "companyName": "杭州第一技师学院",
- "domain": "hzdyjs.edu.cn",
- "status": "0"
- }
- ]
- }
- }
- ```
- **响应参数说明**:
- | 参数名 | 类型 | 说明 |
- | ------------- | ------- | ------------------ |
- | tenantEnabled | boolean | 是否启用多租户功能 |
- | voList | array | 租户列表 |
- **voList 中每项参数**:
- | 参数名 | 类型 | 说明 |
- | ----------- | ------ | ------------------- |
- | tenantId | string | 租户 ID |
- | companyName | string | 租户名称 |
- | domain | string | 租户域名 |
- | status | string | 状态(0 正常 1 停用) |
- ---
- ## 1. 物业报修管理 API
- ### 1.1 维修分类管理
- #### 查询维修分类列表
- **接口地址**: `GET /hq/pm/repairCategory/list`
- **接口描述**: 分页查询维修分类列表,支持权限过滤
- **权限要求**: `pm:category:list`
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------------ | ------ | ---- | --------------------- |
- | pageNum | int | 否 | 页码,默认 1 |
- | pageSize | int | 否 | 页大小,默认 10 |
- | categoryName | string | 否 | 分类名称 |
- | categoryCode | string | 否 | 分类编码 |
- | parentId | long | 否 | 父级分类 ID |
- | skillLevel | string | 否 | 技能等级要求 |
- | status | string | 否 | 状态(0-停用,1-正常) |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": {
- "total": 6,
- "rows": [
- {
- "id": 1,
- "categoryName": "电路维修",
- "categoryCode": "ELECTRIC",
- "categoryDescription": "电路、照明、开关、插座等电气设备维修",
- "parentId": 0,
- "ancestorIds": "0",
- "levelDepth": 1,
- "childrenCount": 0,
- "requiredSkills": "电工技能、安全操作",
- "skillLevel": "2",
- "estimatedDuration": 120,
- "standardCost": 200.0,
- "iconUrl": null,
- "colorCode": "#FF6B35",
- "sortOrder": 1,
- "status": "1",
- "usageCount": 0,
- "lastUsedTime": null,
- "remark": null,
- "createTime": "2025-01-23 14:30:00"
- }
- ]
- }
- }
- ```
- #### 获取维修分类树形结构
- **接口地址**: `GET /hq/pm/repairCategory/tree`
- **接口描述**: 获取维修分类的树形结构数据
- **权限要求**: `pm:category:tree`
- **请求参数**: 无
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": [
- {
- "id": 1,
- "categoryName": "电路维修",
- "categoryCode": "ELECTRIC",
- "categoryDescription": "电路、照明、开关、插座等电气设备维修",
- "parentId": 0,
- "children": []
- }
- ]
- }
- ```
- #### 获取维修分类下拉选项
- **接口地址**: `GET /hq/pm/repairCategory/options`
- **接口描述**: 获取维修分类的下拉选项数据,用于表单选择器
- **权限要求**: `pm:category:list`
- **请求参数**: 无
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": [
- {
- "value": 1,
- "label": "电路维修"
- },
- {
- "value": 2,
- "label": "水管维修"
- },
- {
- "value": 3,
- "label": "门窗维修"
- }
- ]
- }
- ```
- **数据格式说明**:
- - **value**: 分类 ID,用于表单提交
- - **label**: 分类名称,用于显示
- - **扁平化处理**: 将树形结构扁平化,便于下拉选择
- **使用场景**:
- - 报修工单创建时选择维修类型
- - 表单编辑时的分类选择
- - 搜索条件中的分类筛选
- #### 获取维修分类详情
- **接口地址**: `GET /hq/pm/repairCategory/{id}`
- **接口描述**: 根据 ID 获取维修分类详细信息
- **权限要求**: `pm:category:query`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------ | ---- | ---- | ------- |
- | id | long | 是 | 分类 ID |
- #### 新增维修分类
- **接口地址**: `POST /hq/pm/repairCategory`
- **接口描述**: 创建新的维修分类
- **权限要求**: `pm:category:add`
- **请求参数**:
- ```json
- {
- "categoryName": "测试维修类型",
- "categoryCode": "TEST_REPAIR",
- "categoryDescription": "这是一个测试的维修类型",
- "parentId": 0,
- "skillLevel": "1",
- "estimatedDuration": 60,
- "standardCost": 100.0,
- "colorCode": "#1890FF",
- "sortOrder": 99,
- "status": "1",
- "remark": "测试数据"
- }
- ```
- ### 1.2 报修工单管理
- #### 查询报修工单列表
- **接口地址**: `GET /hq/pm/repairOrder/list`
- **接口描述**: 分页查询报修工单列表,支持多种条件筛选,根据用户角色进行数据权限过滤
- **权限要求**: `pm:repairOrder:list`
- **数据权限说明**:
- - **超级管理员**: 可查看所有报修工单
- - **物业维修管理员** (role_key: property_maintenance_admin): 可查看所有报修工单
- - **维修人员** (role_key: maintenance_worker): 只能查看自己创建的工单和分配给自己的工单
- - **普通用户**: 只能查看自己创建的工单
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | --------------- | ------ | ---- | --------------- |
- | pageNum | int | 否 | 页码,默认 1 |
- | pageSize | int | 否 | 页大小,默认 10 |
- | orderNo | string | 否 | 工单编号 |
- | title | string | 否 | 报修标题 |
- | repairLocation | string | 否 | 报修地点 |
- | categoryId | long | 否 | 维修类型 ID |
- | priorityLevel | int | 否 | 紧急程度 |
- | reporterName | string | 否 | 报修人姓名 |
- | reporterPhone | string | 否 | 报修人电话 |
- | orderStatus | string | 否 | 工单状态 |
- | assigneeId | long | 否 | 分派维修员 ID |
- | assigneeName | string | 否 | 分派维修员姓名 |
- | createTimeRange | array | 否 | 创建时间范围 |
- | finishTimeRange | array | 否 | 完成时间范围 |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": {
- "total": 1,
- "rows": [
- {
- "id": "1939510596285673473",
- "tenantId": "000000",
- "orderNo": "RO202506300002",
- "title": "详细测试工单 - 会议室投影仪故障",
- "description": "会议室投影仪无法正常启动,显示器黑屏,影响会议正常进行。设备型号:EPSON EB-U05,购买时间:2023年6月。",
- "repairLocation": "行政楼三楼305会议室",
- "categoryId": 1,
- "categoryName": "电路维修",
- "priorityLevel": 2,
- "expectedFinishTime": "2025-07-02 02:25:34",
- "reporterId": 1,
- "reporterName": "测试用户",
- "reporterPhone": "13900139001",
- "reporterDept": "信息技术部",
- "orderStatus": "1",
- "assignTime": null,
- "assigneeId": null,
- "assigneeName": null,
- "assignRemark": null,
- "startTime": null,
- "finishTime": null,
- "totalDuration": null,
- "repairResult": null,
- "usedMaterials": null,
- "followSuggestions": null,
- "evaluationScore": null,
- "evaluationTime": null,
- "attachmentCount": 0,
- "progressCount": 1,
- "cancelReason": null,
- "remark": "设备在保修期内,请联系厂家技术支持",
- "createTime": "2025-06-30 02:25:34",
- "updateTime": "2025-06-30 02:25:34"
- }
- ]
- }
- }
- ```
- #### 生成工单编号
- **接口地址**: `GET /hq/pm/repairOrder/generateOrderNo`
- **接口描述**: 自动生成报修工单编号
- **权限要求**: 无需特殊权限
- **请求参数**: 无
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "RO202506300002",
- "data": null
- }
- ```
- **说明**: 工单编号格式为 `RO + 年月日 + 序号`,如 `RO202506300002`
- #### 获取报修统计数据
- **接口地址**: `GET /hq/pm/repairOrder/statistics`
- **接口描述**: 获取报修工单的统计数据,用于仪表板展示
- **权限要求**: `pm:repairOrder:statistics`
- **访问权限说明**:
- - **超级管理员**: 可以访问统计数据
- - **物业维修管理员** (role_key: property_maintenance_admin): 可以访问统计数据
- - **维修人员** (role_key: maintenance_worker): **无权限访问**
- - **普通用户**: **无权限访问**
- **请求参数**: 无
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": {
- "totalOrders": 156,
- "pendingAssign": 23,
- "inProgress": 45,
- "completed": 88,
- "cancelled": 0,
- "avgProcessTime": 2.5,
- "avgEvaluationScore": 4.3,
- "monthlyNewOrders": 67,
- "monthlyCompletedOrders": 52,
- "statusDistribution": [
- {
- "status": "待分派",
- "count": 23,
- "percentage": 14.7
- },
- {
- "status": "进行中",
- "count": 45,
- "percentage": 28.8
- },
- {
- "status": "已完成",
- "count": 88,
- "percentage": 56.4
- }
- ],
- "categoryDistribution": [
- {
- "categoryName": "电路维修",
- "count": 45,
- "percentage": 28.8
- },
- {
- "categoryName": "水管维修",
- "count": 38,
- "percentage": 24.4
- }
- ],
- "priorityDistribution": [
- {
- "priorityLevel": 1,
- "count": 12,
- "percentage": 7.7
- },
- {
- "priorityLevel": 2,
- "count": 34,
- "percentage": 21.8
- }
- ]
- }
- }
- ```
- **统计字段说明**:
- | 字段名 | 类型 | 说明 |
- | ---------------------- | ----- | ---------------------- |
- | totalOrders | int | 总工单数量 |
- | pendingAssign | int | 待分派工单数 |
- | inProgress | int | 进行中工单数 |
- | completed | int | 已完成工单数 |
- | cancelled | int | 已取消工单数 |
- | avgProcessTime | float | 平均处理时长(小时) |
- | avgEvaluationScore | float | 平均评价得分(1-5 分) |
- | monthlyNewOrders | int | 本月新增工单数 |
- | monthlyCompletedOrders | int | 本月完成工单数 |
- | statusDistribution | array | 各状态分布统计 |
- | categoryDistribution | array | 各类型分布统计 |
- | priorityDistribution | array | 紧急程度分布统计 |
- **使用场景**:
- - 报修管理仪表板数据展示
- - 运营分析和报表生成
- - 工单处理效率监控
- - 维修类型热度分析
- **注意事项**:
- - 当前版本返回模拟数据,用于前端开发测试
- - 生产环境需要实现真实的统计计算逻辑
- - 统计数据会根据用户权限进行过滤
- #### 获取报修工单详情
- **接口地址**: `GET /hq/pm/repairOrder/{id}`
- **接口描述**: 根据 ID 获取报修工单详细信息,用于前端详情弹窗展示完整工单信息
- **权限要求**: `pm:repairOrder:query`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------ | ---- | ---- | ------- |
- | id | long | 是 | 工单 ID |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": {
- "id": 1001,
- "orderNo": "RO20250126001",
- "title": "宿舍A304水龙头漏水",
- "description": "水龙头一直滴水,影响正常使用,需要及时维修",
- "repairLocation": "学生宿舍A栋304室",
- "categoryId": 102,
- "categoryName": "水管维修",
- "priorityLevel": 2,
- "expectedFinishTime": "2025-01-27 18:00:00",
- "reporterId": 10001,
- "reporterName": "张小明",
- "reporterPhone": "13800138001",
- "reporterDept": "计算机学院",
- "orderStatus": "1",
- "assignTime": null,
- "assigneeId": null,
- "assigneeName": null,
- "assignRemark": null,
- "startTime": null,
- "finishTime": null,
- "totalDuration": null,
- "repairResult": null,
- "usedMaterials": null,
- "followSuggestions": null,
- "evaluationScore": null,
- "evaluationTime": null,
- "attachmentCount": 0,
- "progressCount": 1,
- "cancelReason": null,
- "remark": null,
- "createTime": "2025-01-26 10:30:00",
- "updateTime": "2025-01-26 10:30:00"
- }
- }
- ```
- **前端使用说明**:
- - 该接口用于工单详情弹窗展示,返回 RepairOrderVO 完整对象
- - 前端根据字段是否有值决定显示哪些信息区域:
- - 基本信息:工单编号、状态、紧急程度、创建时间、标题、问题描述
- - 报修信息:报修人、联系电话、部门、期望完成时间、报修地点
- - 维修信息:维修员、时间节点、处理时长、进度记录、分派备注
- - 维修结果:维修结果、使用材料、后续建议
- - 评价信息:综合评分、评价时间
- - 其他信息:附件数量、维修类型、取消原因、备注信息
- - 支持响应式布局,在移动端和桌面端都有良好展示
- #### 新增报修工单
- **接口地址**: `POST /hq/pm/repairOrder`
- **接口描述**: 创建新的报修工单
- **权限要求**: `pm:repairOrder:add`
- **请求参数**:
- ```json
- {
- "orderNo": "RO202506300002",
- "title": "详细测试工单 - 会议室投影仪故障",
- "description": "会议室投影仪无法正常启动,显示器黑屏,影响会议正常进行。设备型号:EPSON EB-U05,购买时间:2023年6月。",
- "repairLocation": "行政楼三楼305会议室",
- "categoryId": 1,
- "priorityLevel": 2,
- "expectedFinishTime": "2025-07-02 02:25:34",
- "reporterName": "测试用户",
- "reporterPhone": "13900139001",
- "reporterDept": "信息技术部",
- "remark": "设备在保修期内,请联系厂家技术支持"
- }
- ```
- **字段说明**:
- | 字段名 | 类型 | 必填 | 说明 |
- | ------------------ | ------ | ---- | -------------------------------------------------------- |
- | orderNo | string | 是 | 工单编号 |
- | title | string | 是 | 报修标题 |
- | description | string | 是 | 问题描述 |
- | repairLocation | string | 是 | 报修地点 |
- | categoryId | long | 是 | 维修类型 ID |
- | priorityLevel | int | 是 | 紧急程度:1-非常紧急,2-紧急,3-一般,4-不紧急,5-可延后 |
- | expectedFinishTime | string | 否 | 期望完成时间 |
- | reporterName | string | 是 | 报修人姓名 |
- | reporterPhone | string | 是 | 报修人电话 |
- | reporterDept | string | 否 | 报修人部门 |
- | remark | string | 否 | 备注信息 |
- ### 1.3 工单操作管理
- #### 分派工单
- **接口地址**: `PUT /hq/pm/repairOrder/{orderId}/assign`
- **接口描述**: 将工单分派给维修人员
- **权限要求**: `pm:repairOrder:assign`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------- | ---- | ---- | ------- |
- | orderId | long | 是 | 工单 ID |
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------------ | ------ | ---- | ------------ |
- | assigneeId | long | 是 | 维修员 ID |
- | assignRemark | string | 否 | 分派备注说明 |
- #### 开始维修
- **接口地址**: `PUT /hq/pm/repairOrder/{orderId}/start`
- **接口描述**: 维修人员开始处理工单
- **权限要求**: `pm:repairOrder:start`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------- | ---- | ---- | ------- |
- | orderId | long | 是 | 工单 ID |
- #### 完成维修
- **接口地址**: `PUT /hq/pm/repairOrder/{orderId}/finish`
- **接口描述**: 标记工单为已完成
- **权限要求**: `pm:repairOrder:finish`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------- | ---- | ---- | ------- |
- | orderId | long | 是 | 工单 ID |
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------------- | ------ | ---- | ------------ |
- | repairResult | string | 否 | 维修结果描述 |
- | usedMaterials | string | 否 | 使用材料清单 |
- #### 取消工单
- **接口地址**: `PUT /hq/pm/repairOrder/{orderId}/cancel`
- **接口描述**: 取消工单
- **权限要求**: `pm:repairOrder:cancel`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------- | ---- | ---- | ------- |
- | orderId | long | 是 | 工单 ID |
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------------ | ------ | ---- | -------- |
- | cancelReason | string | 否 | 取消原因 |
- #### 获取工单进度列表
- **接口地址**: `GET /hq/pm/repairOrder/{orderId}/progress`
- **接口描述**: 获取指定工单的进度记录列表,按时间顺序展示工单处理进度
- **权限要求**: `pm:repairOrder:progress`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": [
- {
- "id": 1,
- "orderId": 1,
- "progressType": "1",
- "progressStatus": "工单已分派",
- "progressDetail": "工单已分派给维修人员zwc007",
- "operatorId": 1,
- "operatorName": "管理员",
- "createTime": "2025-06-30 09:00:00"
- },
- {
- "id": 2,
- "orderId": 1,
- "progressType": "2",
- "progressStatus": "接收确认",
- "progressDetail": "维修人员已接收工单,准备前往现场",
- "operatorId": 7,
- "operatorName": "zwc007",
- "createTime": "2025-06-30 09:30:00"
- }
- ]
- }
- ```
- **错误码**:
- | 错误码 | 说明 | 解决方案 |
- |--------|------|----------|
- | 403 | 无权限 | 确认用户有查看进度权限 |
- | 404 | 工单不存在 | 检查工单 ID 是否正确 |
- #### 更新维修进度
- **接口地址**: `POST /hq/pm/repairOrder/progress`
- **接口描述**: 维修人员更新工单维修进度,保存真实进度记录到数据库,首次更新时自动将工单状态从"已分派"改为"进行中"
- **权限要求**: `pm:repairOrder:updateProgress`
- **业务逻辑**:
- - 保存进度记录到`pm_repair_progress`表
- - 如果是首次更新进度(工单状态为"已分派"),自动将状态改为"进行中"
- - 自动设置`start_time`开始处理时间
- - 更新工单的`progress_count`统计字段
- - 完整的权限验证和数据权限控制
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- | progressType | String | Y | 进度类型:1-工单分派,2-接收确认,3-到达现场,4-开始维修,5-进度更新,6-完成维修,7-用户评价,8-工单归档,9-其他 | "5" |
- | progressStatus | String | Y | 进度状态描述 | "现场检查中" |
- | progressDetail | String | Y | 进度详细说明 | "已到达现场,正在检查设备状态" |
- | locationInfo | String | N | 位置信息 | "教学楼 A 座 201" |
- | estimatedDuration | Integer | N | 预计用时(分钟) | 120 |
- | nextStep | String | N | 下一步计划 | "安装新部件" |
- | issuesEncountered | String | N | 遇到的问题 | "部分线路老化需要更换" |
- | materialsNeeded | String | N | 所需材料 | "电线、插座" |
- | remark | String | N | 备注信息 | "进度顺利" |
- **状态自动流转**:
- - 当工单状态为"已分派"(2)时,首次更新进度将自动触发状态流转为"进行中"(3)
- - 同时设置工单的`start_time`为当前时间
- - 后续进度更新不再触发状态变化
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": null
- }
- ```
- **错误码**:
- | 错误码 | 说明 | 解决方案 |
- |--------|------|----------|
- | 400001 | 工单不存在 | 检查工单 ID |
- | 400002 | 无权限操作该工单 | 检查用户权限 |
- | 400003 | 只能为已分派或进行中状态的工单更新进度 | 工单状态必须为"已分派"(2)或"进行中"(3) |
- | 500001 | 进度记录保存失败 | 联系系统管理员 |
- #### 完成工单(详细版)
- **接口地址**: `PUT /hq/pm/repairOrder/{orderId}/complete`
- **接口描述**: 完成工单并填写维修结果,将工单状态从"进行中"改为"已完成",同时记录完成时间和处理时长
- **权限要求**: `pm:repairOrder:complete`
- **业务逻辑**:
- - 验证工单状态必须为"进行中"(3)
- - 自动计算处理时长(基于开始时间和完成时间)
- - 更新工单状态为"已完成"(4)
- - 自动添加完成进度记录
- - 完成的权限验证和数据权限控制
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID(路径参数) | 1 |
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | repairResult | String | Y | 维修结果描述 | "电路故障已修复,更换了老化线路和插座" |
- | usedMaterials | String | N | 使用材料清单 | "电线 2 米、插座 1 个、绝缘胶带 1 卷" |
- | followSuggestions | String | N | 后续建议 | "建议半年后进行一次电路安全检查" |
- **状态流转**:
- - 只有"进行中"(3)状态的工单才能完成
- - 完成后状态自动变为"已完成"(4)
- - 自动设置`finish_time`完成时间
- - 自动计算`total_duration`处理时长
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": null
- }
- ```
- **错误码**:
- | 错误码 | 说明 | 解决方案 |
- |--------|------|----------|
- | 400001 | 工单不存在 | 检查工单 ID |
- | 400002 | 无权限操作该工单 | 检查用户权限 |
- | 400003 | 只能完成进行中状态的工单 | 工单状态必须为"进行中"(3) |
- | 500001 | 工单完成状态更新失败 | 联系系统管理员 |
- #### 创建服务评价
- **接口地址**: `POST /hq/pm/repairOrder/evaluation`
- **接口描述**: 对已完成的工单进行服务评价,支持多维度评分
- **权限要求**: `pm:repairOrder:evaluate`
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- | evaluatedWorkerId | Long | N | 被评价的维修员 ID | 7 |
- | overallScore | Integer | Y | 综合评分(1-5) | 5 |
- | qualityScore | Integer | N | 质量评分(1-5) | 5 |
- | attitudeScore | Integer | N | 态度评分(1-5) | 4 |
- | responseSpeedScore | Integer | N | 响应速度评分(1-5) | 5 |
- | communicationScore | Integer | N | 沟通评分(1-5) | 4 |
- | evaluationContent | String | Y | 评价内容 | "维修及时,服务态度好" |
- | satisfactionLevel | String | N | 满意度等级 | "1" |
- | isAnonymous | Integer | N | 是否匿名(0 否 1 是) | 0 |
- | isPublic | Integer | N | 是否公开(0 否 1 是) | 1 |
- | positiveTags | String | N | 正面标签 | "专业,及时" |
- | negativeTags | String | N | 负面标签 | "" |
- | improvementSuggestions | String | N | 改进建议 | "无" |
- | remark | String | N | 备注 | "" |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "服务评价提交成功",
- "data": null
- }
- ```
- **错误码**:
- | 错误码 | 说明 | 解决方案 |
- |--------|------|----------|
- | 400 | 参数错误 | 检查评分范围和必填参数 |
- | 403 | 无权限 | 确认用户有评价权限 |
- | 409 | 重复评价 | 该工单已有评价记录 |
- #### 获取服务评价
- **接口地址**: `GET /hq/pm/repairOrder/{orderId}/evaluation`
- **接口描述**: 获取指定工单的服务评价信息
- **权限要求**: `pm:repairOrder:query`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": {
- "id": 1,
- "orderId": 1,
- "overallScore": 5,
- "qualityScore": 5,
- "attitudeScore": 4,
- "responseSpeedScore": 5,
- "communicationScore": 4,
- "evaluationContent": "维修及时,服务态度好,质量可靠。",
- "satisfactionLevel": "1",
- "createTime": "2025-06-30 16:00:00"
- }
- }
- ```
- **错误码**:
- | 错误码 | 说明 | 解决方案 |
- |--------|------|----------|
- | 403 | 无权限 | 确认用户有查询权限 |
- | 404 | 评价不存在 | 该工单暂无评价记录 |
- #### 获取维修人员选项
- **接口地址**: `GET /hq/pm/repairOrder/maintenance-workers`
- **接口描述**: 获取拥有"维修人员"角色的用户选项列表,用于分派工单时选择维修员
- **权限要求**: `pm:repairOrder:assign`
- **排序规则**: 返回的维修人员选项按用户名(`user_name`)升序排列,便于快速定位目标用户
- **请求参数**: 无
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "操作成功",
- "data": [
- {
- "value": 7,
- "label": "zwc007 - 智胜技术开发团队",
- "userName": "zwc007",
- "deptName": "智胜技术开发团队"
- }
- ]
- }
- ```
- **错误码**:
- | 错误码 | 说明 | 解决方案 |
- |--------|------|----------|
- | 403 | 无权限 | 确认用户有分派权限 |
- ### 1.4 工单状态说明
- | 状态值 | 状态名称 | 说明 |
- | ------ | -------- | -------------------- |
- | 1 | 待分派 | 工单已创建,等待分派 |
- | 2 | 已分派 | 已分派给维修人员 |
- | 3 | 进行中 | 维修人员正在处理 |
- | 4 | 已完成 | 维修工作已完成 |
- | 5 | 已评价 | 用户已对服务进行评价 |
- | 6 | 已归档 | 工单已归档 |
- | 9 | 已取消 | 工单已被取消 |
- ### 1.5 紧急程度说明
- | 级别值 | 级别名称 | 说明 |
- | ------ | -------- | ------------------------ |
- | 1 | 非常紧急 | 影响正常运营,需立即处理 |
- | 2 | 紧急 | 影响使用,需尽快处理 |
- | 3 | 一般 | 正常维修需求 |
- | 4 | 不紧急 | 可延后处理 |
- | 5 | 可延后 | 条件允许时处理 |
- ---
- ## 2. 问卷管理 API
- ### 1.1 问卷基础管理
- #### 查询问卷列表
- **接口地址**: `GET /hq/satSurvey/list`
- **接口描述**: 分页查询问卷列表,支持权限过滤
- **权限要求**: `hq:satSurvey:list`
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ----------- | ------ | ---- | --------------------- |
- | pageNum | int | 否 | 页码,默认 1 |
- | pageSize | int | 否 | 页大小,默认 10 |
- | surveyCode | string | 否 | 问卷编号 |
- | surveyTitle | string | 否 | 问卷标题 |
- | targetGroup | string | 否 | 目标群体 |
- | status | string | 否 | 问卷状态 |
- | isPublished | int | 否 | 是否发布(1 是 0 否) |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": {
- "total": 100,
- "rows": [
- {
- "id": 1,
- "surveyCode": "SURVEY001",
- "surveyTitle": "满意度调查",
- "surveyDesc": "学生满意度调查",
- "targetGroup": "1",
- "startTime": "2025-01-01 00:00:00",
- "endTime": "2025-01-31 23:59:59",
- "isAnonymous": 1,
- "isPublished": 1,
- "status": "1"
- }
- ]
- }
- }
- ```
- #### 获取问卷详情
- **接口地址**: `GET /hq/satSurvey/{id}`
- **接口描述**: 根据 ID 获取问卷详细信息
- **权限要求**: `hq:satSurvey:query`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------ | ---- | ---- | ------- |
- | id | long | 是 | 问卷 ID |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": {
- "id": 1,
- "surveyCode": "SURVEY001",
- "surveyTitle": "满意度调查",
- "surveyDesc": "学生满意度调查",
- "surveyInstruction": "请认真填写",
- "targetGroup": "1",
- "startTime": "2025-01-01 00:00:00",
- "endTime": "2025-01-31 23:59:59",
- "maxSubmitTimes": 1,
- "isAnonymous": 1,
- "isPublished": 1,
- "status": "1",
- "remark": ""
- }
- }
- ```
- #### 新增问卷
- **接口地址**: `POST /hq/satSurvey`
- **接口描述**: 创建新的问卷
- **权限要求**: `hq:satSurvey:add`
- **请求参数**:
- ```json
- {
- "surveyCode": "SURVEY001",
- "surveyTitle": "满意度调查",
- "surveyDesc": "学生满意度调查",
- "surveyInstruction": "请认真填写",
- "targetGroup": "1",
- "startTime": "2025-01-01 00:00:00",
- "endTime": "2025-01-31 23:59:59",
- "maxSubmitTimes": 1,
- "isAnonymous": 1,
- "remark": ""
- }
- ```
- #### 修改问卷
- **接口地址**: `PUT /hq/satSurvey`
- **接口描述**: 修改问卷信息
- **权限要求**: `hq:satSurvey:edit`
- #### 删除问卷
- **接口地址**: `DELETE /hq/satSurvey/{ids}`
- **接口描述**: 批量删除问卷
- **权限要求**: `hq:satSurvey:remove`
- #### 发布问卷
- **接口地址**: `PUT /hq/satSurvey/{id}/publish`
- **接口描述**: 发布问卷,将状态改为进行中
- **权限要求**: `hq:satSurvey:publish`
- #### 撤销发布问卷
- **接口地址**: `PUT /hq/satSurvey/{id}/unpublish`
- **接口描述**: 撤销发布问卷,将状态改为草稿
- **权限要求**: `hq:satSurvey:unpublish`
- ### 1.2 问卷题目管理
- #### 获取问卷题目列表
- **接口地址**: `GET /hq/satSurvey/{surveyId}/questions`
- **接口描述**: 获取问卷关联的题目列表,包含题目详细信息和选项
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | -------- | ---- | ---- | ------- |
- | surveyId | long | 是 | 问卷 ID |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": [
- {
- "id": 1,
- "surveyId": 1,
- "questionId": 1,
- "sortOrder": 1,
- "weight": 1,
- "isRequired": 1,
- "questionTitle": "您对服务质量的评价?",
- "questionType": "1",
- "questionDesc": "请选择一个选项",
- "options": [
- {
- "id": 1,
- "questionId": 1,
- "optionValue": "A",
- "optionText": "非常满意",
- "optionScore": 5,
- "sortOrder": 1
- }
- ]
- }
- ]
- }
- ```
- #### 更新问卷题目关联
- **接口地址**: `PUT /hq/satSurvey/{surveyId}/questions`
- **接口描述**: 批量更新问卷题目关联关系
- **权限要求**: `hq:satSurvey:question`
- ---
- ## 2. 答题 API(新增)
- ### 2.1 答题提交
- #### 提交问卷答案
- **接口地址**: `POST /hq/satSurvey/answer/submit`
- **接口描述**: 提交问卷答案,正式提交后不可修改
- **权限要求**: 需要登录
- **请求参数**:
- ```json
- {
- "surveyId": 1,
- "startTime": "2025-01-26T14:00:00.000Z",
- "endTime": "2025-01-26T14:15:00.000Z",
- "isAnonymous": 1,
- "answers": [
- {
- "questionId": 1,
- "questionType": "1",
- "answerValue": "A",
- "options": [
- {
- "optionId": 1,
- "optionValue": "A",
- "optionText": "非常满意",
- "isSelected": true
- }
- ]
- },
- {
- "questionId": 2,
- "questionType": "2",
- "answerValue": "A,C,D",
- "options": [
- {
- "optionId": 2,
- "optionValue": "A",
- "optionText": "选项A",
- "isSelected": true
- },
- {
- "optionId": 4,
- "optionValue": "C",
- "optionText": "选项C",
- "isSelected": true
- }
- ]
- },
- {
- "questionId": 3,
- "questionType": "3",
- "answerValue": "这是我的意见和建议内容",
- "options": []
- }
- ],
- "remark": ""
- }
- ```
- **参数说明**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ----------- | ------ | ---- | ----------------------------- |
- | surveyId | long | 是 | 问卷 ID |
- | startTime | string | 是 | 答题开始时间(ISO 8601 格式) |
- | endTime | string | 是 | 答题结束时间(ISO 8601 格式) |
- | isAnonymous | int | 是 | 是否匿名(1 是 0 否) |
- | answers | array | 是 | 答案列表 |
- | remark | string | 否 | 备注 |
- **answers 中每项参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ------------ | ------ | ---- | ------------------------------------------------ |
- | questionId | long | 是 | 题目 ID |
- | questionType | string | 是 | 题目类型(1 单选题 2 多选题 3 问答题) |
- | answerValue | string | 是 | 答案值(单选存选项值,多选逗号分隔,问答存文本) |
- | options | array | 否 | 选项详情(单选题和多选题需要) |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "答题提交成功",
- "data": {
- "id": 1001,
- "surveyId": 1,
- "userId": 1,
- "userType": "student",
- "submitTime": "2025-01-26T14:15:00.000Z",
- "totalScore": 0,
- "avgScore": 0,
- "remark": ""
- }
- }
- ```
- **多次提交功能说明**(v1.0.3 新增,v1.0.4 优化):
- 系统支持问卷多次提交功能,提交次数限制由问卷的 `max_submit_times` 字段控制:
- 1. **提交次数规则**:
- - `max_submit_times = 0`: 不限制提交次数,用户可以无限次提交
- - `max_submit_times = 1`: 最多提交 1 次(默认行为,向后兼容)
- - `max_submit_times = N`: 最多提交 N 次
- 2. **数据存储策略**(v1.0.4 重要更新):
- - **软删除历史数据**: 用户提交新答案时,系统会自动将之前的答题记录标记为已删除(deleted=1)
- - **保持数据完整性**: 历史数据完整保留用于审计,但业务查询只返回最新有效数据
- - **关联删除**: 通过 record_id 关联,确保 hq_sat_record、hq_sat_detail、hq_sat_answer 三表数据状态同步
- 3. **数据状态管理**:
- - `deleted = 0`: 有效数据,正常业务查询可见
- - `deleted = 1`: 历史数据,仅审计查询可见
- - 用户每次只能看到最新的有效答题记录
- 4. **处理流程**:
- ```
- 用户提交新答案 → 标记历史数据为删除 → 保存新答题数据 → 返回最新记录
- ```
- 5. **错误处理**:
- ```json
- {
- "code": 500,
- "msg": "您已达到该问卷的最大提交次数限制(3次)",
- "data": null
- }
- ```
- 6. **使用场景**:
- - **单次提交**: 正式考试、重要调研等
- - **多次提交**: 练习测试、阶段性评估等
- - **无限提交**: 学习练习、反馈收集等
- 7. **业务优势**:
- - ✅ **用户体验**: 查看答题记录始终是最新版本
- - ✅ **数据审计**: 历史记录完整保留,支持数据回溯
- - ✅ **查询性能**: 业务查询只涉及有效数据,提高效率
- - ✅ **数据一致性**: 避免多版本数据混乱问题
- **数据保存说明**:
- 此接口在保存答题记录时,会同时保存详细的答案信息到两个表:
- 1. **hq_sat_detail 表**:保存答题概要信息
- - 记录答题记录 ID、题目 ID、答案分数等基础信息
- - remark 字段存储答案内容的摘要信息
- 2. **hq_sat_answer 表**:保存具体的答案详情(v1.0.1 新增,v1.0.2 修复)
- - **单选题**:为选中的选项创建一条记录,包含选项 ID、选项标识(A/B/C/D)、选项文本、真实分值
- - **多选题**:为每个选中的选项创建一条记录,使用选项标识区分不同选项
- - **问答题**:创建一条记录,选项相关字段为 NULL,答案值存储用户输入的文本内容
- **hq_sat_answer 表数据示例**(v1.0.2 修复后):
- ```sql
- -- 单选题答案记录(用户选择"非常满意"选项)
- INSERT INTO hq_sat_answer VALUES (
- 1, '000000', 1001, NOW(), 1, NOW(), 0, -- 基础字段
- 123, 1, '1', 1, 'A', '非常满意', 'A', 5, NULL -- 答案字段
- );
- -- 多选题答案记录(用户选中A、C两个选项)
- INSERT INTO hq_sat_answer VALUES
- (2, '000000', 1001, NOW(), 1, NOW(), 0, 123, 2, '2', 1, 'A', '非常满意', 'A,C', 5, NULL),
- (3, '000000', 1001, NOW(), 1, NOW(), 0, 123, 2, '2', 3, 'C', '一般', 'A,C', 1, NULL);
- -- 问答题答案记录
- INSERT INTO hq_sat_answer VALUES (
- 4, '000000', 1001, NOW(), 1, NOW(), 0, -- 基础字段
- 123, 3, '3', NULL, NULL, NULL, '这是我的意见和建议', 0, NULL -- 答案字段
- );
- ```
- **字段说明**(修复后):
- - `option_value`: 存储选项标识(A、B、C、D),便于统计分析
- - `answer_score`: 存储真实分值(从 hq_sat_option 表查询获得)
- - `answer_value`: 单选题存选项标识,多选题存逗号分隔的多个标识,问答题存文本
- #### 保存问卷答案草稿
- **接口地址**: `POST /hq/satSurvey/answer/draft`
- **接口描述**: 保存问卷答案草稿,可多次保存和修改
- **权限要求**: 需要登录
- **请求参数**: 同提交问卷答案
- **响应示例**: 同提交问卷答案
- ### 2.2 答题状态查询
- #### 检查用户是否已答过问卷
- **接口地址**: `GET /hq/satSurvey/{surveyId}/answered`
- **接口描述**: 检查当前用户是否已经答过指定问卷(v1.0.3 更新:支持多次提交检查)
- **权限要求**: 需要登录
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | -------- | ---- | ---- | ------- |
- | surveyId | long | 是 | 问卷 ID |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": true
- }
- ```
- **响应说明**(v1.0.3 更新):
- - `data` 为 `true` 表示用户已答过该问卷(至少提交过 1 次)
- - `data` 为 `false` 表示用户未答过该问卷
- **多次提交支持**:
- 此接口仅返回用户是否有答题记录,不考虑提交次数限制。要检查是否还能继续提交,请参考以下逻辑:
- - 如果 `max_submit_times = 0`:始终可以提交
- - 如果 `max_submit_times > 0`:需要检查用户提交次数是否小于此限制
- - 具体的提交限制检查由"提交问卷答案"接口在提交时进行
- #### 获取用户问卷答题记录
- **接口地址**: `GET /hq/satSurvey/{surveyId}/answer`
- **接口描述**: 获取当前用户对指定问卷的答题记录(v1.0.5 重大更新:优化数据源,支持前端答案回显)
- **权限要求**: 需要登录
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | -------- | ---- | ---- | ------- |
- | surveyId | long | 是 | 问卷 ID |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": {
- "id": 1001,
- "surveyId": 1,
- "userId": 1,
- "userType": "student",
- "submitTime": "2025-01-26T14:15:00.000Z",
- "totalScore": 0,
- "avgScore": 0,
- "remark": "ANSWERS_DATA:[{\"questionId\":1,\"questionType\":\"1\",\"answerValue\":\"A\"},{\"questionId\":2,\"questionType\":\"2\",\"answerValue\":\"A,C\"}]"
- }
- }
- ```
- **返回数据说明**(v1.0.5 重大更新):
- - 此接口只返回用户最新的有效答题记录(deleted=0)
- - 如果用户进行了多次提交,历史记录已被软删除,查询不到
- - 返回的是用户最后一次提交的完整答题信息
- - 历史记录完整保留在数据库中,仅用于审计目的
- **v1.0.5 新增功能 - 答案回显数据**:
- 为支持前端答题界面的历史答案回显功能,此接口现在会在 `remark` 字段中包含格式化的答案数据:
- 1. **数据格式**: `ANSWERS_DATA:[答案JSON数组]`
- 2. **数据来源**: 直接从 `hq_sat_answer` 表查询,比 v1.0.4 之前的 `remark` 解析更准确
- 3. **答案结构**:
- ```json
- [
- {
- "questionId": 1,
- "questionType": "1",
- "answerValue": "A"
- },
- {
- "questionId": 2,
- "questionType": "2",
- "answerValue": "A,C"
- },
- {
- "questionId": 3,
- "questionType": "3",
- "answerValue": "用户输入的文本内容"
- }
- ]
- ```
- **前端答案回显逻辑**:
- - **单选题** (`questionType = "1"`): `answerValue` 直接设置到单选控件(如 "A")
- - **多选题** (`questionType = "2"`): `answerValue` 按逗号分割成数组(如 ["A", "C"])
- - **问答题** (`questionType = "3"`): `answerValue` 直接设置到文本框
- **使用场景**:
- - ✅ **首次答题**: 返回 404,前端正常显示空表单
- - ✅ **重新答题**: 返回历史答案,前端自动回显到表单
- - ✅ **多次修改**: 基于上次答案继续编辑,提升用户体验
- ---
- ## 3. 题目管理 API
- ### 3.1 题目基础管理
- #### 查询题目列表
- **接口地址**: `GET /hq/satQuestion/list`
- **权限要求**: `hq:satQuestion:list`
- #### 获取题目选项
- **接口地址**: `GET /hq/satQuestion/{questionId}/options`
- **接口描述**: 获取指定题目的所有选项
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 |
- | ---------- | ---- | ---- | ------- |
- | questionId | long | 是 | 题目 ID |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": [
- {
- "id": 1,
- "questionId": 1,
- "optionValue": "A",
- "optionText": "非常满意",
- "optionScore": 5,
- "sortOrder": 1
- },
- {
- "id": 2,
- "questionId": 1,
- "optionValue": "B",
- "optionText": "满意",
- "optionScore": 4,
- "sortOrder": 2
- }
- ]
- }
- ```
- ---
- ## 4. 答题记录管理 API
- ### 4.1 答题记录查询
- #### 查询答题记录列表
- **接口地址**: `GET /hq/satRecord/list`
- **权限要求**: `hq:satRecord:list`
- #### 获取答题记录详情
- **接口地址**: `GET /hq/satRecord/{id}`
- **权限要求**: `hq:satRecord:query`
- ---
- ## 5. 错误码说明
- ### 业务错误码
- | 错误码 | 说明 | 解决方案 |
- | ------ | ------------------ | ------------------------ |
- | 40001 | 问卷不存在 | 检查问卷 ID 是否正确 |
- | 40002 | 问卷未在进行中状态 | 等待问卷开始或联系管理员 |
- | 40003 | 您已经答过这份问卷 | 不能重复答题 |
- | 40004 | 答题记录保存失败 | 重新提交或联系技术支持 |
- | 40005 | 题目类型不支持 | 检查题目类型是否正确 |
- ---
- ## 6. 数据字典
- ### 6.1 问卷状态
- | 值 | 说明 | 备注 |
- | --- | ------ | -------------- |
- | 0 | 草稿 | 未发布状态 |
- | 1 | 进行中 | 已发布,可答题 |
- | 2 | 已结束 | 超过结束时间 |
- ### 6.2 目标群体
- | 值 | 说明 | 备注 |
- | --- | ------ | ---------- |
- | 1 | 学生 | 在校学生 |
- | 2 | 教职工 | 教师和职工 |
- | 3 | 全体 | 所有人员 |
- ### 6.4 用户类型
- | 值 | 说明 | 备注 |
- | --- | ---------- | --------------------------------------------------------- |
- | 1 | 学生 | student、学生、stu 等角色映射为此值 |
- | 2 | 教师 | teacher、老师、教师、教职工、tea 等角色映射为此值 |
- | 3 | 超级管理员 | admin、管理员、超级管理员、administrator 等角色映射为此值 |
- ### 6.3 题目类型
- | 值 | 说明 | 备注 |
- | --- | ------ | ---------------- |
- | 1 | 单选题 | 只能选择一个选项 |
- | 2 | 多选题 | 可以选择多个选项 |
- | 3 | 问答题 | 文本输入 |
- ---
- ## 7. 版本更新记录
- ### v1.0.5 (2025-01-26)
- - 🚀 **重大更新**:实现答题界面历史答案回显功能,提升多次答题用户体验
- - 🔧 **数据源优化**:`GET /hq/satSurvey/{surveyId}/answer` 接口改用 hq_sat_answer 表直接查询
- - 📊 新增 `getAnswersFromSatAnswerTable()` 方法,提供更准确的答案数据聚合
- - ✨ 前端新增 `loadPreviousAnswers()` 方法,支持三种题型的智能答案回显
- - 🎯 智能用户体验:只在成功加载历史答案时显示提示,异常时优雅降级
- - 🛡️ 错误处理优化:404 错误不显示提示,历史答案加载失败不阻断答题流程
- ### v1.0.4 (2025-01-26)
- - 🔄 **重要优化**:多次提交时实现历史数据软删除,确保用户只有一份有效答题记录
- - 🗃️ 保留历史数据用于审计,但业务查询只返回最新有效数据
- - ⚡ 优化查询性能,提交次数统计和答题记录查询只涉及有效数据
- - 🛡️ 增强数据一致性,通过 record_id 关联确保三表数据状态同步
- ### v1.0.3 (2025-01-26)
- - 🚀 **新功能**:实现问卷多次提交功能,支持根据 max_submit_times 设置控制提交次数
- - 📊 优化提交次数检查逻辑,支持 0=无限制、N=最大 N 次的灵活配置
- - ✅ 保留完整的答题历史记录,每次提交创建新的答题记录
- - 🎯 增强用户体验,提供详细的提交次数限制提示信息
- ### v1.0.2 (2025-01-26)
- - 🔧 **重要修复**:修复单选题和多选题答案未记录到 hq_sat_answer 表的问题
- - 🎯 修复前端选项绑定使用分值导致的数据类型不匹配问题
- - ✅ 优化答案保存逻辑,正确存储选项标识(A、B、C、D)和分值
- - 📊 增强答案数据查询,支持选项分值自动计算
- - 🐛 修复多选题答案保存逻辑错误
- ### v1.0.1 (2025-01-26)
- - 🔧 修复答题提交时 user_type 字段长度问题
- - ✅ 新增用户角色到数字编码的转换逻辑
- - 📚 新增用户类型数据字典说明
- - 🆕 新增答案详情记录功能,同时保存到 hq_sat_answer 表
- - 📝 完善提交问卷答案接口的数据保存说明
- ### v1.0.0 (2025-01-26)
- - ✅ 新增答题提交 API
- - ✅ 新增答题状态查询 API
- - ✅ 完善问卷管理 API
- - ✅ 新增题目选项查询 API
- - ✅ 建立完整的 API 文档体系
- ---
- ## 8. 开发说明
- ### 8.1 接口测试
- 推荐使用以下工具进行接口测试:
- - **Postman**: 图形化接口测试工具
- - **Apifox**: 国产 API 管理工具
- - **curl**: 命令行工具
- ### 8.2 认证方式
- 所有需要权限的接口都需要在请求头中携带认证信息:
- ```http
- Authorization: Bearer {token}
- ```
- ### 8.3 时间格式
- 所有时间字段统一使用 ISO 8601 格式:
- ```
- 2025-01-26T14:15:00.000Z
- ```
- ### 8.4 分页参数
- 所有分页接口统一使用以下参数:
- - `pageNum`: 页码,从 1 开始
- - `pageSize`: 页大小,默认 10
- ---
- ## 联系方式
- 如有 API 相关问题,请联系开发团队或查看项目仓库的 Issues。
- ---
- ### 分派工单
- **接口地址**: `PUT /hq/pm/repairOrder/{orderId}/assign`
- **接口描述**: 分派工单给维修员
- **权限要求**: `pm:repairOrder:assign`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | assigneeId | Long | Y | 维修员 ID | 2 |
- | assignRemark | String | N | 分派备注 | "紧急处理" |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "分派成功",
- "data": null
- }
- ```
- **错误码**:
- | 错误码 | 说明 | 解决方案 |
- |--------|------|----------|
- | 400001 | 工单不存在 | 检查工单 ID |
- | 400002 | 维修员不存在 | 检查维修员 ID |
- | 400003 | 工单状态不允许分派 | 检查工单状态 |
- ---
- ### 获取工单进度列表
- **接口地址**: `GET /hq/pm/repairOrder/{orderId}/progress`
- **接口描述**: 获取指定工单的进度记录列表
- **权限要求**: `pm:repairOrder:progress`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": [
- {
- "id": 1,
- "orderId": 1,
- "progressType": "5",
- "progressStatus": "正在维修",
- "progressDetail": "已到达现场,开始检查设备",
- "operatorId": 2,
- "operatorName": "张维修",
- "operatorRole": "worker",
- "locationInfo": "教学楼A座301",
- "estimatedDuration": 60,
- "operationTime": "2025-06-30 14:30:00",
- "nextStep": "更换零件",
- "issuesEncountered": "发现零件老化",
- "materialsNeeded": "电路板x1",
- "remark": "需要采购新零件"
- }
- ]
- }
- ```
- ---
- ### 更新维修进度
- **接口地址**: `POST /hq/pm/repairOrder/progress`
- **接口描述**: 添加工单维修进度记录
- **权限要求**: `pm:repairOrder:updateProgress`
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- | progressType | String | Y | 进度类型:1-工单分派,2-接收确认,3-到达现场,4-开始维修,5-进度更新,6-完成维修,7-用户评价,8-工单归档,9-其他 | "5" |
- | progressStatus | String | Y | 进度状态描述 | "正在维修" |
- | progressDetail | String | Y | 进度详细描述 | "已到达现场,开始检查设备" |
- | locationInfo | String | N | 操作位置信息 | "教学楼 A 座 301" |
- | estimatedDuration | Integer | N | 预计耗时(分钟) | 60 |
- | nextStep | String | N | 下一步计划 | "更换零件" |
- | issuesEncountered | String | N | 遇到的问题 | "发现零件老化" |
- | materialsNeeded | String | N | 需要的材料 | "电路板 x1" |
- | remark | String | N | 备注信息 | "需要采购新零件" |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "进度更新成功",
- "data": null
- }
- ```
- ---
- ### 完成工单
- **接口地址**: `PUT /hq/pm/repairOrder/{orderId}/finish`
- **接口描述**: 完成工单维修,填写维修结果
- **权限要求**: `pm:repairOrder:complete`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | repairResult | String | Y | 维修结果描述 | "已更换故障电路板,设备恢复正常" |
- | usedMaterials | String | N | 使用材料清单 | "电路板 x1, 螺丝 x4" |
- | followSuggestions | String | N | 后续建议 | "建议定期检查电路板状态" |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "工单完成成功",
- "data": null
- }
- ```
- ---
- ### 创建服务评价
- **接口地址**: `POST /hq/pm/repairOrder/evaluation`
- **接口描述**: 创建工单服务评价
- **权限要求**: `pm:repairOrder:evaluate`
- **请求参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- | evaluatedWorkerId | Long | Y | 被评价维修员 ID | 2 |
- | overallScore | Number | Y | 综合评价得分(1.0-5.0) | 4.5 |
- | qualityScore | Number | Y | 维修质量得分(1.0-5.0) | 4.8 |
- | attitudeScore | Number | Y | 服务态度得分(1.0-5.0) | 4.5 |
- | responseSpeedScore | Number | Y | 响应速度得分(1.0-5.0) | 4.2 |
- | communicationScore | Number | Y | 沟通效果得分(1.0-5.0) | 4.6 |
- | evaluationContent | String | Y | 文字评价内容 | "维修师傅技术过硬,态度很好" |
- | satisfactionLevel | String | Y | 满意度等级:1-非常满意,2-满意,3-一般,4-不满意,5-非常不满意 | "1" |
- | isAnonymous | Integer | N | 是否匿名评价:0-否,1-是 | 0 |
- | isPublic | Integer | N | 是否公开显示:0-否,1-是 | 1 |
- | positiveTags | String | N | 正面标签 | "技术专业,态度友好" |
- | negativeTags | String | N | 负面标签 | "" |
- | improvementSuggestions | String | N | 改进建议 | "希望能提前通知到达时间" |
- | remark | String | N | 备注信息 | "" |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "评价提交成功",
- "data": null
- }
- ```
- ---
- ### 获取工单评价
- **接口地址**: `GET /hq/pm/repairOrder/{orderId}/evaluation`
- **接口描述**: 获取指定工单的服务评价信息
- **权限要求**: `pm:repairOrder:query`
- **路径参数**:
- | 参数名 | 类型 | 必填 | 说明 | 示例值 |
- |--------|------|------|------|--------|
- | orderId | Long | Y | 工单 ID | 1 |
- **响应示例**:
- ```json
- {
- "code": 200,
- "msg": "查询成功",
- "data": {
- "id": 1,
- "orderId": 1,
- "evaluatorId": 3,
- "evaluatorName": "张老师",
- "evaluatedWorkerId": 2,
- "evaluatedWorkerName": "张维修",
- "overallScore": 4.5,
- "qualityScore": 4.8,
- "attitudeScore": 4.5,
- "responseSpeedScore": 4.2,
- "communicationScore": 4.6,
- "evaluationContent": "维修师傅技术过硬,态度很好",
- "satisfactionLevel": "1",
- "isAnonymous": 0,
- "isPublic": 1,
- "positiveTags": "技术专业,态度友好",
- "improvementSuggestions": "希望能提前通知到达时间",
- "evaluationTime": "2025-06-30 16:30:00"
- }
- }
- ```
- ---
|