zentao-api 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- (()=>{var{defineProperty:f,getOwnPropertyNames:ZQ,getOwnPropertyDescriptor:zQ}=Object,xQ=Object.prototype.hasOwnProperty;function SQ(Q){return this[Q]}var PQ=(Q)=>{var X=(YQ??=new WeakMap).get(Q),$;if(X)return X;if(X=f({},"__esModule",{value:!0}),Q&&typeof Q==="object"||typeof Q==="function"){for(var J of ZQ(Q))if(!xQ.call(X,J))f(X,J,{get:SQ.bind(Q,J),enumerable:!($=zQ(Q,J))||$.enumerable})}return YQ.set(Q,X),X},YQ;var EQ=(Q)=>Q;function NQ(Q,X){this[Q]=EQ.bind(null,X)}var HQ=(Q,X)=>{for(var $ in X)f(Q,$,{get:X[$],enumerable:!0,configurable:!0,set:NQ.bind(X,$)})};var YX={};HQ(YX,{switchProfile:()=>P,setGlobalOptions:()=>I,request:()=>QQ,getProfileKey:()=>V,getProfile:()=>s,getModuleAction:()=>N,getModule:()=>j,getGlobalOptions:()=>R,getAllProfiles:()=>i,deleteProfile:()=>l,defineModules:()=>r,defineModuleActions:()=>e,addProfile:()=>S,ZentaoError:()=>H,ZentaoClient:()=>T,ZENTAO_PROFILES_STORAGE_KEY:()=>z,VERSION:()=>$Q,ERRORS:()=>g,BUILD:()=>XQ});var b={};HQ(b,{switchProfile:()=>P,setGlobalOptions:()=>I,request:()=>QQ,getProfileKey:()=>V,getProfile:()=>s,getModuleAction:()=>N,getModule:()=>j,getGlobalOptions:()=>R,getAllProfiles:()=>i,deleteProfile:()=>l,defineModules:()=>r,defineModuleActions:()=>e,addProfile:()=>S,ZentaoError:()=>H,ZentaoClient:()=>T,ZENTAO_PROFILES_STORAGE_KEY:()=>z,VERSION:()=>$Q,ERRORS:()=>g,BUILD:()=>XQ});var g={E_INVALID_BASE_URL:"Invalid ZenTao baseUrl.",E_NO_GLOBAL_CLIENT:"No global client configured. Call ZentaoClient.init() or pass options.client.",E_HTTP_ERROR:"HTTP request failed: {status} {statusText}",E_NETWORK_ERROR:"Network request failed: {message}",E_TIMEOUT:"Request timed out.",E_INSECURE_BROWSER:"The insecure option is only supported in Node.js runtimes.",E_LOGIN_FAILED:"ZenTao login failed.",E_INVALID_PROFILE:"Invalid ZenTao profile.",E_NO_PROFILE:"No ZenTao profile is configured.",E_PROFILE_NOT_FOUND:"ZenTao profile not found: {profileKey}",E_PROFILE_STORAGE_INVALID:"ZenTao profile storage is not valid JSON.",E_PROFILE_STORAGE_UNAVAILABLE:"ZenTao profile storage is unavailable in this runtime.",E_INVALID_MODULE:"Unknown module: {module}",E_INVALID_ACTION:"Unknown action: {module}-{action}",E_INVALID_MODULE_DEFINITION:"Invalid module definition.",E_INVALID_ACTION_DEFINITION:"Invalid module action definition.",E_MISSING_PARAM:"Missing required parameter: {param}",E_INVALID_PARAM:"Invalid value for parameter {param}: {value}",E_INVALID_REQUEST_NAME:'Request name must use the form "moduleName/methodName".',E_API_FAILED:"ZenTao API returned failure: {message}"};class H extends Error{code;details;constructor(Q,X,$){let J=g[Q];if(X)for(let[W,G]of Object.entries(X))J=J.replaceAll(`{${W}}`,String(G));super(J);this.name="ZentaoError",this.code=Q,this.details=$}}function h(){return typeof process<"u"&&Boolean(process.versions?.node)}function GQ(Q){return import(Q)}function gQ(Q){let X={};return new Headers(Q).forEach(($,J)=>{X[J]=$}),X}function hQ(Q){let X=new Headers;for(let[$,J]of Object.entries(Q)){if(J===void 0)continue;X.set($,Array.isArray(J)?J.join(", "):String(J))}return X}async function kQ(Q){if(Q===void 0||Q===null)return;if(typeof Q==="string")return Q;if(Q instanceof Uint8Array)return Q;if(Q instanceof ArrayBuffer)return new Uint8Array(Q);if(ArrayBuffer.isView(Q))return new Uint8Array(Q.buffer,Q.byteOffset,Q.byteLength);if(Q instanceof Blob)return new Uint8Array(await Q.arrayBuffer());return String(Q)}function qQ(){return new DOMException("The operation was aborted.","AbortError")}function bQ(Q){let X=Q.reduce((W,G)=>W+G.byteLength,0),$=new Uint8Array(X),J=0;for(let W of Q)$.set(W,J),J+=W.byteLength;return $.buffer}async function fQ(Q,X,$){let J=new URL(Q),W=J.protocol==="https:"?await GQ("node:https"):await GQ("node:http"),G=await kQ(X.body);return new Promise((q,B)=>{if(X.signal?.aborted){B(qQ());return}let D=W.request(J,{method:X.method??"GET",headers:gQ(X.headers),rejectUnauthorized:$},(Y)=>{let A=[];Y.on("data",(L)=>{A.push(typeof L==="string"?new TextEncoder().encode(L):L)}),Y.on("end",()=>{M();let L=A.length>0?bQ(A):void 0,O=new Response(L,{status:Y.statusCode??200,statusText:Y.statusMessage??"",headers:hQ(Y.headers)});Object.defineProperty(O,"url",{value:Q}),q(O)})}),M=()=>{X.signal?.removeEventListener("abort",C)},C=()=>{M(),D.destroy(qQ())};if(D.on("error",(Y)=>{M(),B(Y)}),X.signal?.addEventListener("abort",C,{once:!0}),G!==void 0)D.write(G);D.end()})}function y(Q){if(Q&&!h())throw new H("E_INSECURE_BROWSER")}async function BQ(Q,X,$){if(!Q)return fetch(X,$);return y(Q),fQ(X,$,!1)}var v={};function R(){return{...v}}function I(Q){v={...v,...Q}}function w(Q){return Boolean(Q)&&typeof Q==="object"&&!Array.isArray(Q)}function _(Q){let X=Q.trim().replace(/\/+$/,"");if(!X)throw new H("E_INVALID_BASE_URL");let $=X.replace(/\/api\.php\/v2$/i,""),J;try{J=new URL($)}catch{throw new H("E_INVALID_BASE_URL")}if(!["http:","https:"].includes(J.protocol)||J.search||J.hash)throw new H("E_INVALID_BASE_URL");return J.toString().replace(/\/+$/,"")}function c(Q,X){let $=X.split("."),J=Q;for(let W of $){if(J===null||J===void 0||typeof J!=="object")return;J=J[W]}return J}function m(Q){return Array.isArray(Q)?Q:[Q]}var z="ZENTAO_PROFILES",yQ=[".config","zentao","zentao.json"];function CQ(Q){return Boolean(Q)&&typeof Q==="object"&&!Array.isArray(Q)}function MQ(Q){if(Q===void 0)return Q;return JSON.parse(JSON.stringify(Q))}function LQ(){return new Date().toISOString()}function Z(Q){return import(Q)}var AQ=Promise.resolve();function d(Q){let X=AQ.then(Q,Q);return AQ=X.catch(()=>{return}),X}function FQ(){try{return globalThis.localStorage}catch{return}}async function VQ(){let Q=await Z("node:path"),X=process.env.HOME??process.env.USERPROFILE??(await Z("node:os")).homedir();if(!X)throw new H("E_PROFILE_STORAGE_UNAVAILABLE");return Q.join(X,...yQ)}function vQ(Q,X){let $=Q.trim(),J=_(X);if(!$)throw new H("E_INVALID_PROFILE");return`${$}@${J}`}function p(Q){if(!CQ(Q)||typeof Q.server!=="string"||typeof Q.account!=="string"||typeof Q.token!=="string")throw new H("E_INVALID_PROFILE");let X=Q.token.trim();if(!X)throw new H("E_INVALID_PROFILE");let $=MQ(Q);return delete $.key,{...$,server:_(Q.server),account:Q.account.trim(),token:X}}function RQ(Q){if(!CQ(Q))return{profiles:[]};let X=Array.isArray(Q.profiles)?Q.profiles.flatMap((J)=>{try{return[p(J)]}catch{return[]}}):[],$=typeof Q.currentProfile==="string"?Q.currentProfile:void 0;return $?{currentProfile:$,profiles:X}:{profiles:X}}function DQ(Q){try{return RQ(JSON.parse(Q))}catch(X){throw new H("E_PROFILE_STORAGE_INVALID",void 0,X)}}async function x(){if(h()){let $=await Z("node:fs/promises"),J=await VQ();try{return DQ(await $.readFile(J,"utf8"))}catch(W){if(W.code==="ENOENT")return{profiles:[]};throw W}}let Q=FQ();if(!Q)throw new H("E_PROFILE_STORAGE_UNAVAILABLE");let X=Q.getItem(z);return X?DQ(X):{profiles:[]}}async function u(Q){let X=RQ(Q),$=`${JSON.stringify(X,null,2)}
2
- `;if(h()){let W=await Z("node:fs/promises"),G=await Z("node:path"),q=await VQ(),B=G.dirname(q),D=G.join(B,`.zentao.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`);await W.mkdir(B,{recursive:!0,mode:448}),await W.chmod(B,448).catch(()=>{return});try{await W.writeFile(D,$,{encoding:"utf8",mode:384}),await W.rename(D,q),await W.chmod(q,384).catch(()=>{return})}catch(M){throw await W.rm(D,{force:!0}).catch(()=>{return}),M}return}let J=FQ();if(!J)throw new H("E_PROFILE_STORAGE_UNAVAILABLE");J.setItem(z,$)}function k(Q){let X=p(Q);return{...MQ(X),key:V(X)}}function n(Q,X){return Q.profiles.find(($)=>V($)===X)}function cQ(Q){if(!Q.currentProfile||!n(Q,Q.currentProfile)){let X=Q.profiles.at(-1);Q.currentProfile=X?V(X):void 0}}function V(Q){return vQ(Q.account,Q.server)}async function i(){return(await x()).profiles.map(k)}async function s(Q){let X=await x(),$=Q??X.currentProfile;if(!$)return;let J=n(X,$);return J?k(J):void 0}function S(Q){return d(async()=>{let X=await x(),$=LQ(),J=p({...Q,loginTime:Q.loginTime??$,lastUsedTime:Q.lastUsedTime??$}),W=V(J),G=X.profiles.findIndex((q)=>V(q)===W);if(G>=0)X.profiles[G]=J;else X.profiles.push(J);return X.currentProfile=W,await u(X),k(J)})}function l(Q){return d(async()=>{let X=await x(),$=X.profiles.filter((J)=>V(J)!==Q);if($.length===X.profiles.length)return!1;return X.profiles=$,cQ(X),await u(X),!0})}function P(Q){return d(async()=>{let X=await x(),$=Q??X.currentProfile;if(!$)throw new H("E_NO_PROFILE");let J=n(X,$);if(!J)throw new H("E_PROFILE_NOT_FOUND",{profileKey:$});return J.lastUsedTime=LQ(),X.currentProfile=$,await u(X),k(J)})}var mQ=1e4;function dQ(Q,X,$){let J=X.startsWith("/")?X:`/${X}`,W=new URL(`${Q}${J}`);for(let[G,q]of Object.entries($??{})){if(q===void 0)continue;W.searchParams.set(G,String(q))}return W.toString()}async function pQ(Q){let X=await Q.text();if(X==="")return;try{return JSON.parse(X)}catch{return X}}class T{siteUrl;baseUrl;token;timeout;insecure;constructor(Q){let X=typeof Q==="string"?{baseUrl:Q}:Q;this.siteUrl=_(X.baseUrl),this.baseUrl=`${this.siteUrl}/api.php/v2`,this.token=X.token,this.timeout=X.timeout,this.insecure=X.insecure}async request(Q,X={}){let $=R(),J=X.method??"GET",W=X.timeout??$.timeout??this.timeout??mQ,G=X.insecure??$.insecure??this.insecure;y(G);let q=dQ(this.baseUrl,Q,X.query),B=new AbortController,D=setTimeout(()=>B.abort(),W),M={};if(this.token)M.Token=this.token;let C={method:J,headers:M,signal:B.signal};if(X.body!==void 0&&J!=="GET")M["Content-Type"]="application/json",C.body=JSON.stringify(X.body);try{let Y=await BQ(G,q,C);if(!Y.ok)throw new H("E_HTTP_ERROR",{status:Y.status,statusText:Y.statusText},{url:Y.url,status:Y.status,statusText:Y.statusText,body:await Y.text().catch(()=>{return})});return pQ(Y)}catch(Y){if(Y instanceof H)throw Y;if(Y instanceof DOMException&&Y.name==="AbortError")throw new H("E_TIMEOUT");throw new H("E_NETWORK_ERROR",{message:Y.message??String(Y)},Y)}finally{clearTimeout(D)}}async get(Q){return this.request(Q,{method:"GET"})}async post(Q,X){return this.request(Q,{method:"POST",body:X})}async put(Q,X){return this.request(Q,{method:"PUT",body:X})}async delete(Q){return this.request(Q,{method:"DELETE"})}async login(Q,X){let $=await this.post("/users/login",{account:Q,password:X});if($.status!=="success"||!$.token)throw new H("E_LOGIN_FAILED");this.token=$.token;let J=R();if(J.persistProfiles){let W={},G=this.timeout??J.timeout,q=this.insecure??J.insecure;if(G!==void 0)W.timeout=G;if(q!==void 0)W.insecure=q;await S({server:this.siteUrl,account:Q,token:$.token,user:w($.user)?$.user:void 0,serverConfig:w($.serverConfig)?$.serverConfig:void 0,config:Object.keys(W).length>0?W:void 0})}return $.token}static create(Q){return new T(Q)}static init(Q){let X=new T(Q);return I({client:X}),X}static async fromProfile(Q){let X=await P(Q);return new T({baseUrl:X.server,token:X.token,timeout:typeof X.config?.timeout==="number"?X.config.timeout:void 0,insecure:typeof X.config?.insecure==="boolean"?X.config.insecure:void 0})}}var KQ=[{name:"user",display:"用户",description:"用户管理,支持获取用户列表、创建用户、获取用户详情、修改用户信息、删除用户",actions:[{name:"list",display:"获取用户列表",type:"list",method:"get",path:"/users",resultType:"list",pagerGetter:"pager",resultGetter:"users",params:[{name:"browseType",required:!1,type:"string",description:"浏览类型",options:[{value:"inside",label:"内部用户"},{value:"outside",label:"内部用户"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"realname_asc",label:"姓名 升序"},{value:"realname_desc",label:"姓名 降序"},{value:"account_asc",label:"用户名 升序"},{value:"account_desc",label:"用户名 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建用户",type:"create",method:"post",path:"/users",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{account:{type:"string",description:"登录名"},realname:{type:"string",description:"姓名"},password:{type:"string",description:"密码"}},required:["account","realname","password"]}}},{name:"get",display:"获取用户详情",type:"get",method:"get",path:"/users/{userID}",resultType:"object",resultGetter:"user",pathParams:{userID:"用户ID"}},{name:"update",display:"修改用户信息",type:"update",method:"put",path:"/users/{userID}",resultType:"object",pathParams:{userID:"用户ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{realname:{type:"string",description:"真实姓名"},dept:{type:"integer",description:"部门",format:"int32"},join:{type:"string",description:"入职日期"},group:{type:"array",items:{type:"string"},description:"权限分组"},email:{type:"string",description:"邮箱"},visions:{type:"array",items:{type:"string"},description:"界面类型(研发综合界面 rnd | 运营管理界面 lite)"},mobile:{type:"string",description:"手机"},weixin:{type:"string",description:"微信"},password:{type:"string",description:"密码"}}}}},{name:"delete",display:"删除用户",type:"delete",method:"delete",path:"/users/{userID}",resultType:"text",pathParams:{userID:"用户ID"},render:"action"}]},{name:"program",display:"项目集",description:"项目集管理,支持获取项目集列表、创建项目集、获取项目集详情、修改项目集、删除项目集",actions:[{name:"list",display:"获取项目集列表",type:"list",method:"get",path:"/programs",resultType:"list",pagerGetter:"pager",resultGetter:"programs",params:[{name:"status",required:!1,type:"string",description:"状态",options:[{value:"all",label:"全部"},{value:"unclosed",label:"未关闭"},{value:"wait",label:"未开始"},{value:"doing",label:"进行中"},{value:"suspended",label:"已挂起"},{value:"delayed",label:"已延期"},{value:"closed",label:"已关闭"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"name_asc",label:"名称 升序"},{value:"name_desc",label:"名称 降序"},{value:"begin_asc",label:"计划开始 升序"},{value:"begin_desc",label:"计划开始 降序"},{value:"end_asc",label:"计划结束 升序"},{value:"end_desc",label:"计划结束 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建项目集",type:"create",method:"post",path:"/programs",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"项目集名称"},begin:{type:"string",description:"计划开始日期"},end:{type:"string",description:"计划完成日期"},PM:{type:"string",description:"计划完成日期"},desc:{type:"string",description:"项目集描述"}},required:["name","begin","end"]}}},{name:"get",display:"获取项目集详情",type:"get",method:"get",path:"/programs/{programID}",resultType:"object",resultGetter:"program",pathParams:{programID:"项目集ID"}},{name:"update",display:"修改项目集",type:"update",method:"put",path:"/programs/{programID}",resultType:"object",pathParams:{programID:"项目集ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"项目集名称"},begin:{type:"string",description:"计划开始日期"},end:{type:"string",description:"计划完成日期"},PM:{type:"string",description:"计划完成日期"},desc:{type:"string",description:"项目集描述"}},required:["name","begin","end"]}}},{name:"delete",display:"删除项目集",type:"delete",method:"delete",path:"/programs/{programID}",resultType:"text",pathParams:{programID:"项目集ID"},render:"action"}]},{name:"product",display:"产品",description:"产品管理,支持获取产品列表、创建产品、获取产品详情、修改产品、删除产品",actions:[{name:"list",display:"获取产品列表",type:"list",method:"get",path:"/products",resultType:"list",pagerGetter:"pager",resultGetter:"products",params:[{name:"browseType",required:!1,type:"string",description:"浏览类型",options:[{value:"all",label:"全部"},{value:"noclosed",label:"未关闭"},{value:"closed",label:"已结束"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"名称 升序"},{value:"title_desc",label:"名称 降序"},{value:"begin_asc",label:"计划开始 升序"},{value:"begin_desc",label:"计划开始 降序"},{value:"end_asc",label:"计划结束 升序"},{value:"end_desc",label:"计划结束 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建产品",type:"create",method:"post",path:"/products",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"产品名称"},program:{type:"integer",description:"所属项目集",format:"int32"},line:{type:"integer",description:"所属产品线",format:"int32"},type:{type:"string",description:"类型(normal 正常 | branch 多分支 | platform 多平台)"},PO:{type:"string",description:"产品负责人"},reviewer:{type:"array",items:{type:"string"},description:"评审人"},desc:{type:"array",items:{type:"string"},description:"产品描述"},QD:{type:"string",description:"测试负责人"},RD:{type:"string",description:"发布负责人"},acl:{type:"string",description:"访问控制(open 公开 | private 私有)"}},required:["name"]}}},{name:"get",display:"获取产品详情",type:"get",method:"get",path:"/products/{productID}",resultType:"object",resultGetter:"product",pathParams:{productID:"产品ID"}},{name:"update",display:"修改产品",type:"update",method:"put",path:"/products/{productID}",resultType:"object",pathParams:{productID:"产品ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"产品名称"},program:{type:"integer",description:"所属项目集",format:"int32"},line:{type:"integer",description:"所属产品线",format:"int32"},type:{type:"string",description:"类型(normal 正常 | branch 多分支 | platform 多平台)"},PO:{type:"string",description:"产品负责人"},reviewer:{type:"array",items:{type:"string"},description:"评审人"},desc:{type:"array",items:{type:"string"},description:"产品描述"},QD:{type:"string",description:"测试负责人"},RD:{type:"string",description:"发布负责人"},acl:{type:"string",description:"访问控制(open 公开 | private 私有)"}},required:["name"]}}},{name:"delete",display:"删除产品",type:"delete",method:"delete",path:"/products/{productID}",resultType:"text",pathParams:{productID:"产品ID"},render:"action"}]},{name:"project",display:"项目",description:"项目管理,支持获取项目列表、创建项目、修改项目、删除项目",actions:[{name:"list",display:"获取项目列表",type:"list",method:"get",path:"/projects",resultType:"list",pagerGetter:"pager",resultGetter:"projects",params:[{name:"browseType",required:!1,type:"string",description:"项目状态,默认是undone",defaultValue:"undone",options:[{value:"all",label:"全部"},{value:"undone",label:"未完成"},{value:"wait",label:"未开始"},{value:"doing",label:"进行中"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"name_asc",label:"名称 升序"},{value:"name_desc",label:"名称 降序"},{value:"begin_asc",label:"计划开始 升序"},{value:"begin_desc",label:"计划开始 降序"},{value:"end_asc",label:"计划结束 升序"},{value:"end_desc",label:"计划结束 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建项目",type:"create",method:"post",path:"/projects",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"项目名称"},model:{type:"string",description:"项目管理方式(scrum 敏捷 | waterfall 瀑布 | kanban 看板 | agileplus 融合敏捷 | waterfallplus 融合瀑布)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},products:{type:"array",items:{type:"string"},description:"关联产品"},parent:{type:"integer",description:"所属项目集",format:"int32"},workflowGroup:{type:"integer",description:"项目流程,付费版功能,开源版可以不填",format:"int32"},PM:{type:"string",description:"项目负责人"}},required:["name","model","begin","end","workflowGroup"]}}},{name:"update",display:"修改项目",type:"update",method:"put",path:"/projects/{projectID}",resultType:"object",pathParams:{projectID:"项目ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"项目名称"},model:{type:"string",description:"项目管理方式(scrum 敏捷 | waterfall 瀑布 | kanban 看板 | agileplus 融合敏捷 | waterfallplus 融合瀑布)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},products:{type:"array",items:{type:"string"},description:"关联产品"},parent:{type:"integer",description:"所属项目集",format:"int32"},workflowGroup:{type:"integer",description:"项目流程,付费版功能,开源版可以不填",format:"int32"},PM:{type:"string",description:"项目负责人"}},required:["name","model","begin","end","workflowGroup"]}}},{name:"delete",display:"删除项目",type:"delete",method:"delete",path:"/projects/{projectID}",resultType:"text",pathParams:{projectID:"项目ID"},render:"action"}]},{name:"execution",display:"执行",description:"执行管理,支持获取执行列表、创建执行、获取执行详情、修改执行、删除执行",actions:[{name:"list",display:"获取执行列表",type:"list",method:"get",path:"/executions",resultType:"list",pagerGetter:"pager",resultGetter:"executions",params:[{name:"status",required:!1,type:"string",description:"执行状态,默认是undone",defaultValue:"undone",options:[{value:"all",label:"全部"},{value:"undone",label:"未完成"},{value:"wait",label:"未开始"},{value:"doing",label:"进行中"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"rawID_asc",label:"RAWID 升序"},{value:"rawID_desc",label:"RAWID 降序"},{value:"nameCol_asc",label:"名称 升序"},{value:"nameCol_desc",label:"名称 降序"},{value:"begin_asc",label:"计划开始 升序"},{value:"begin_desc",label:"计划开始 降序"},{value:"end_asc",label:"计划结束 升序"},{value:"end_desc",label:"计划结束 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建执行",type:"create",method:"post",path:"/executions",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{project:{type:"integer",description:"所属项目",format:"int32"},name:{type:"string",description:"迭代名称"},lifetime:{type:"string",description:"执行类型(short 短期 | long 长期 | ops 运维)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},days:{type:"integer",description:"可用工作日",format:"int32"},products:{type:"array",items:{type:"string"},description:"关联产品"},plans:{type:"array",items:{type:"string"},description:"关联计划,必须是产品+planID的二维数组"},PO:{type:"string",description:"产品负责人"},QD:{type:"string",description:"测试负责人"},PM:{type:"string",description:"执行负责人"},RD:{type:"string",description:"发布负责人"},acl:{type:"string",description:"访问控制(open 公开 | private 私有)"}},required:["project","name","begin","end"]}}},{name:"get",display:"获取执行详情",type:"get",method:"get",path:"/executions/{executionID}",resultType:"object",resultGetter:"execution",pathParams:{executionID:"执行ID"}},{name:"update",display:"修改执行",type:"update",method:"put",path:"/executions/{executionID}",resultType:"object",pathParams:{executionID:"执行ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{project:{type:"integer",description:"所属项目",format:"int32"},name:{type:"string",description:"迭代名称"},lifetime:{type:"string",description:"执行类型(short 短期 | long 长期 | ops 运维)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},days:{type:"integer",description:"可用工作日",format:"int32"},products:{type:"array",items:{type:"string"},description:"关联产品"},plans:{type:"array",items:{type:"string"},description:"关联计划,必须是产品+planID的二维数组"},PO:{type:"string",description:"产品负责人"},QD:{type:"string",description:"测试负责人"},PM:{type:"string",description:"执行负责人"},RD:{type:"string",description:"发布负责人"},acl:{type:"string",description:"访问控制(open 公开 | private 私有)"}},required:["name","begin","end"]}}},{name:"delete",display:"删除执行",type:"delete",method:"delete",path:"/executions/{executionID}",resultType:"text",pathParams:{executionID:"执行ID"},render:"action"}]},{name:"productplan",display:"产品计划",description:"产品计划管理,支持获取产品计划列表,支持获取产品下的产品计划、创建产品计划、获取产品计划详情、修改产品计划、删除产品计划",actions:[{name:"list",display:"获取产品计划列表,支持获取产品下的产品计划",type:"list",method:"get",path:"/{scope}/{scopeID}/productplans",resultType:"list",pagerGetter:"pager",resultGetter:"productplans",pathParams:{scope:{description:"产品计划范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"执行状态,默认是undone",defaultValue:"undone",options:[{value:"all",label:"全部"},{value:"undone",label:"未完成"},{value:"wait",label:"未开始"},{value:"doing",label:"进行中"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"名称 升序"},{value:"title_desc",label:"名称 降序"},{value:"begin_asc",label:"开始日期 升序"},{value:"begin_desc",label:"开始日期 降序"},{value:"end_asc",label:"结束日期 升序"},{value:"end_desc",label:"结束日期 降序"},{value:"status_asc",label:"状态 升序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建产品计划",type:"create",method:"post",path:"/productplans",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"产品ID",format:"int32"},title:{type:"string",description:"计划名称"},parent:{type:"integer",description:"父计划ID",format:"int32"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},branchID:{type:"integer",description:"分支ID",format:"int32"},desc:{type:"string",description:"计划描述"}},required:["productID","title"]}}},{name:"get",display:"获取产品计划详情",type:"get",method:"get",path:"/productplans/{planID}",resultType:"object",resultGetter:"productplan",pathParams:{planID:"产品计划ID"}},{name:"update",display:"修改产品计划",type:"update",method:"put",path:"/productplans/{productplanID}",resultType:"object",pathParams:{productplanID:"产品计划ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"计划名称"},parent:{type:"integer",description:"父计划",format:"int32"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},branchID:{type:"integer",description:"分支ID",format:"int32"},desc:{type:"string",description:"计划描述"}},required:["title"]}}},{name:"delete",display:"删除产品计划",type:"delete",method:"delete",path:"/productplans/{productplanID}",resultType:"text",pathParams:{productplanID:"产品计划ID"},render:"action"}]},{name:"story",display:"需求",description:"需求管理,支持获取需求列表,支持获取产品/项目/执行下的需求、创建需求、获取需求详情、修改需求、删除需求、激活需求、变更需求、关闭需求",actions:[{name:"list",display:"获取需求列表,支持获取产品/项目/执行下的需求",type:"list",method:"get",path:"/{scope}/{scopeID}/stories",resultType:"list",pagerGetter:"pager",resultGetter:"stories",pathParams:{scope:{description:"需求范围",options:[{value:"products",label:"产品"},{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"allstory",label:"全部"},{value:"assignedtome",label:"指派给我"},{value:"openedbyme",label:"我创建"},{value:"reviewbyme",label:"待我评审"},{value:"draftstory",label:"草稿"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建需求",type:"create",method:"post",path:"/stories",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"产品ID",format:"int32"},title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},spec:{type:"string",description:"需求描述"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},verify:{type:"string",description:"验收标准"},assignedTo:{type:"string",description:"指派给"},reviewer:{type:"array",items:{type:"string"},description:"评审人,如果设置必须评审,必须填写"},project:{type:"integer",description:"所属项目",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"}},required:["productID","title"]}}},{name:"get",display:"获取需求详情",type:"get",method:"get",path:"/stories/{storyID}",resultType:"object",resultGetter:"story",pathParams:{storyID:"需求ID"}},{name:"update",display:"修改需求",type:"update",method:"put",path:"/stories/{storyID}",resultType:"object",pathParams:{storyID:"需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},assignedTo:{type:"string",description:"指派给"}},required:["title"]}}},{name:"delete",display:"删除需求",type:"delete",method:"delete",path:"/stories/{storyID}",resultType:"text",pathParams:{storyID:"需求ID"},render:"action"},{name:"activate",display:"激活需求",type:"action",method:"put",path:"/stories/{storyID}/activate",resultType:"text",pathParams:{storyID:"需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"change",display:"变更需求",type:"action",method:"put",path:"/stories/{storyID}/change",resultType:"text",pathParams:{storyID:"需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"需求名称"},reviewer:{type:"array",items:{type:"string"},description:"评审人员"},spec:{type:"string",description:"需求描述"},verify:{type:"string",description:"验收标准"}},required:["reviewer"]}},render:"action"},{name:"close",display:"关闭需求",type:"action",method:"put",path:"/stories/{storyID}/close",resultType:"text",pathParams:{storyID:"需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(done 已完成 | subdivided 已拆分 | duplicate 重复 | postponed 延期 | willnotdo 不做 | cancel 已取消 | bydesign 设计如此)"},comment:{type:"string",description:"备注"}},required:["closedReason"]}},render:"action"}]},{name:"epic",display:"业务需求",description:"业务需求管理,支持获取业务需求列表,支持获取产品下的业务需求、创建业务需求、获取业务需求详情、修改业务需求、删除业务需求、激活业务需求、变更业务需求、关闭业务需求",actions:[{name:"list",display:"获取业务需求列表,支持获取产品下的业务需求",type:"list",method:"get",path:"/{scope}/{scopeID}/epics",resultType:"list",pagerGetter:"pager",resultGetter:"epics",pathParams:{scope:{description:"业务需求范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"allstory",label:"全部"},{value:"assignedtome",label:"指派给我"},{value:"openedbyme",label:"我创建"},{value:"reviewbyme",label:"待我评审"},{value:"draftstory",label:"草稿"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建业务需求",type:"create",method:"post",path:"/epics",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"产品ID",format:"int32"},title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父业务需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},spec:{type:"string",description:"业务需求描述"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},verify:{type:"string",description:"验收标准"},assignedTo:{type:"string",description:"指派给"},reviewer:{type:"array",items:{type:"string"},description:"评审人,如果设置必须评审,必须填写"}},required:["productID","title"]}}},{name:"get",display:"获取业务需求详情",type:"get",method:"get",path:"/epics/{storyID}",resultType:"object",resultGetter:"epic",pathParams:{storyID:"需求ID"}},{name:"update",display:"修改业务需求",type:"update",method:"put",path:"/epics/{epicID}",resultType:"object",pathParams:{epicID:"业务需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"需求名称"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父业务需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},assignedTo:{type:"string",description:"指派给"}},required:["title"]}}},{name:"delete",display:"删除业务需求",type:"delete",method:"delete",path:"/epics/{epicID}",resultType:"text",pathParams:{epicID:"业务需求ID"},render:"action"},{name:"activate",display:"激活业务需求",type:"action",method:"put",path:"/epics/{epicID}/activate",resultType:"text",pathParams:{epicID:"业务需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"change",display:"变更业务需求",type:"action",method:"put",path:"/epics/{epicID}/change",resultType:"text",pathParams:{epicID:"业务需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"需求名称"},reviewer:{type:"array",items:{type:"string"},description:"评审人员"},spec:{type:"string",description:"需求描述"},verify:{type:"string",description:"验收标准"}},required:["reviewer"]}},render:"action"},{name:"close",display:"关闭业务需求",type:"action",method:"put",path:"/epics/{epicID}/close",resultType:"text",pathParams:{epicID:"业务需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(done 已完成 | subdivided 已拆分 | duplicate 重复 | postponed 延期 | willnotdo 不做 | cancel 已取消 | bydesign 设计如此)"},comment:{type:"string",description:"备注"}},required:["closedReason"]}},render:"action"}]},{name:"requirement",display:"用户需求",description:"用户需求管理,支持获取用户需求列表,支持获取产品下的用户需求、创建用户需求、获取用户需求详情、修改用户需求、删除用户需求、激活用户需求、变更用户需求、关闭用户需求",actions:[{name:"list",display:"获取用户需求列表,支持获取产品下的用户需求",type:"list",method:"get",path:"/{scope}/{scopeID}/requirements",resultType:"list",pagerGetter:"pager",resultGetter:"requirements",pathParams:{scope:{description:"用户需求范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"allstory",label:"全部"},{value:"assignedtome",label:"指派给我"},{value:"openedbyme",label:"我创建"},{value:"reviewbyme",label:"待我评审"},{value:"draftstory",label:"草稿"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建用户需求",type:"create",method:"post",path:"/requirements",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"产品ID",format:"int32"},title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父用户需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},spec:{type:"string",description:"用户需求描述"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},verify:{type:"string",description:"验收标准"},assignedTo:{type:"string",description:"指派给"},reviewer:{type:"array",items:{type:"string"},description:"评审人,如果设置必须评审,必须填写"}},required:["productID","title"]}}},{name:"get",display:"获取用户需求详情",type:"get",method:"get",path:"/requirements/{storyID}",resultType:"object",resultGetter:"requirement",pathParams:{storyID:"需求ID"}},{name:"update",display:"修改用户需求",type:"update",method:"put",path:"/requirements/{requirementID}",resultType:"object",pathParams:{requirementID:"用户需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父用户需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},assignedTo:{type:"string",description:"指派给"}},required:["title"]}}},{name:"delete",display:"删除用户需求",type:"delete",method:"delete",path:"/requirements/{requirementID}",resultType:"text",pathParams:{requirementID:"用户需求ID"},render:"action"},{name:"activate",display:"激活用户需求",type:"action",method:"put",path:"/requirements/{requirementID}/activate",resultType:"text",pathParams:{requirementID:"用户需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"change",display:"变更用户需求",type:"action",method:"put",path:"/requirements/{requirementID}/change",resultType:"text",pathParams:{requirementID:"用户需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"需求名称"},spec:{type:"string",description:"需求描述"},verify:{type:"string",description:"验收标准"}}}},render:"action"},{name:"close",display:"关闭用户需求",type:"action",method:"put",path:"/requirements/{requirementID}/close",resultType:"text",pathParams:{requirementID:"用户需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(done 已完成 | subdivided 已拆分 | duplicate 重复 | postponed 延期 | willnotdo 不做 | cancel 已取消 | bydesign 设计如此)"},comment:{type:"string",description:"备注"}},required:["closedReason"]}},render:"action"}]},{name:"bug",display:"Bug",description:"Bug管理,支持获取Bug列表,支持获取产品/项目/执行下的Bug、创建Bug、获取Bug详情、修改Bug、删除Bug、激活Bug、关闭Bug、解决Bug",actions:[{name:"list",display:"获取Bug列表,支持获取产品/项目/执行下的Bug",type:"list",method:"get",path:"/{scope}/{scopeID}/bugs",resultType:"list",pagerGetter:"pager",resultGetter:"bugs",pathParams:{scope:{description:"Bug范围",options:[{value:"products",label:"产品"},{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"all",label:"全部"},{value:"unclosed",label:"未关闭"},{value:"assignedtome",label:"指派给我"},{value:"openedbyme",label:"我创建"},{value:"assignedbyme",label:"由我指派"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建Bug",type:"create",method:"post",path:"/bugs",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品",format:"int32"},title:{type:"string",description:"Bug标题"},openedBuild:{type:"array",items:{type:"string"},description:"影响版本,主干是trunk,其他版本使用版本ID"},project:{type:"integer",description:"所属项目",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"},severity:{type:"integer",description:"严重程度,默认是3",format:"int32"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},type:{type:"string",description:"Bug类型(codeerror 代码错误 | config 配置相关 | install 安装部署 | security 安全相关 | performance 性能问题 | standard 标准规范 | automation 测试脚本 | designdefect 设计缺陷 | others 其他)"},steps:{type:"string",description:"重现步骤"},story:{type:"integer",description:"相关需求",format:"int32"}},required:["productID","title","openedBuild"]}}},{name:"get",display:"获取Bug详情",type:"get",method:"get",path:"/bugs/{bugID}",resultType:"object",resultGetter:"bug",pathParams:{bugID:"Bug ID"}},{name:"update",display:"修改Bug",type:"update",method:"put",path:"/bugs/{bugID}",resultType:"object",pathParams:{bugID:"Bug ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"Bug标题"},severity:{type:"integer",description:"严重程度,默认是3",format:"int32"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},type:{type:"string",description:"Bug类型(codeerror 代码错误 | config 配置相关 | install 安装部署 | security 安全相关 | performance 性能问题 | standard 标准规范 | automation 测试脚本 | designdefect 设计缺陷 | others 其他)"},openedBuild:{type:"array",items:{type:"string"},description:"影响版本,主干是trunk,其他版本使用版本ID"},steps:{type:"string",description:"重现步骤"},project:{type:"integer",description:"所属项目",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"}}}}},{name:"delete",display:"删除Bug",type:"delete",method:"delete",path:"/bugs/{bugID}",resultType:"text",pathParams:{bugID:"Bug ID"},render:"action"},{name:"activate",display:"激活Bug",type:"action",method:"put",path:"/bugs/{bugID}/activate",resultType:"text",pathParams:{bugID:"Bug ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{openedBuild:{type:"array",items:{type:"string"},description:"影响版本, trunk为主干"},assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"close",display:"关闭Bug",type:"action",method:"put",path:"/bugs/{bugID}/close",resultType:"text",pathParams:{bugID:"Bug ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{comment:{type:"string",description:"备注"}}}},render:"action"},{name:"resolve",display:"解决Bug",type:"action",method:"put",path:"/bugs/{bugID}/resolve",resultType:"text",pathParams:{bugID:"Bug ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{resolution:{type:"string",description:"fixed 已解决 | notrepro 无法重现 | bydesign 设计如此 | duplicate 重复Bug | external 外部原因| postponed 延期处理 | willnotfix 不予解决 | tostory 转为需求"},resolvedDate:{type:"string",description:"解决日期,默认今天"},resolvedBuild:{type:"string",description:"解决版本, trunk为主干"},assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}},required:["resolution"]}},render:"action"}]},{name:"testcase",display:"测试用例",description:"测试用例管理,支持获取测试用例列表,支持获取产品/项目/执行下的测试用例、创建测试用例、获取测试用例详情、修改测试用例、删除测试用例",actions:[{name:"list",display:"获取测试用例列表,支持获取产品/项目/执行下的测试用例",type:"list",method:"get",path:"/{scope}/{scopeID}/testcases",resultType:"list",pagerGetter:"pager",resultGetter:"testcases",pathParams:{scope:{description:"测试用例范围",options:[{value:"products",label:"产品"},{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是all",defaultValue:"all",options:[{value:"all",label:"全部"},{value:"wait",label:"未关闭"},{value:"needconfirm",label:"需求变动"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建测试用例",type:"create",method:"post",path:"/testcases",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品",format:"int32"},title:{type:"string",description:"用例标题"},module:{type:"integer",description:"所属模块",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"},pri:{type:"integer",description:"优先级",format:"int32"},type:{type:"string",description:"用例类型(unit 单元测试 | interface 接口测试 | feature 功能测试 | install 安装部署 | config 配置相关 | performance 性能测试 | security 安全相关 | other 其他)"},precondition:{type:"string",description:"前置条件"},steps:{type:"array",items:{type:"string"},description:"用例步骤"},expects:{type:"array",items:{type:"string"},description:"用例步骤期望"},stepType:{type:"array",items:{type:"string"},description:"用例步骤类型(step 步骤 | group 父级步骤)"},project:{type:"integer",description:"所属项目",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"}},required:["productID","title"]}}},{name:"get",display:"获取测试用例详情",type:"get",method:"get",path:"/testcases/{caseID}",resultType:"object",resultGetter:"testcase",pathParams:{caseID:"测试用例ID"}},{name:"update",display:"修改测试用例",type:"update",method:"put",path:"/testcases/{testcasID}",resultType:"object",pathParams:{testcasID:"测试用例ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"用例标题"},moudule:{type:"integer",description:"所属模块",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"},pri:{type:"integer",description:"优先级",format:"int32"},type:{type:"string",description:"用例类型(unit 单元测试 | interface 接口测试 | feature 功能测试 | install 安装部署 | config 配置相关 | performance 性能测试 | security 安全相关 | other 其他)"},precondition:{type:"string",description:"前置条件"},steps:{type:"array",items:{type:"string"},description:"用例步骤"},expects:{type:"array",items:{type:"string"},description:"用例步骤期望"},stepType:{type:"array",items:{type:"string"},description:"用例步骤类型(step 步骤 | group 父级步骤)"}},required:["title"]}}},{name:"delete",display:"删除测试用例",type:"delete",method:"delete",path:"/testcases/{testcasID}",resultType:"text",pathParams:{testcasID:"测试用例ID"},render:"action"}]},{name:"task",display:"任务",description:"任务管理,支持获取任务列表,支持获取执行下的任务、创建任务、获取任务详情、修改任务、删除任务、激活任务、关闭任务、完成任务、启动任务",actions:[{name:"list",display:"获取任务列表,支持获取执行下的任务",type:"list",method:"get",path:"/{scope}/{scopeID}/tasks",resultType:"list",pagerGetter:"pager",resultGetter:"tasks",pathParams:{scope:{description:"任务范围",options:[{value:"executions",label:"执行"}]},scopeID:"范围ID"},params:[{name:"status",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"all",label:"全部"},{value:"unclosed",label:"未关闭"},{value:"assignedtome",label:"指派给我"},{value:"assignedtome",label:"指派给我"},{value:"myinvolved",label:"由我参与"},{value:"assignedbyme",label:"由我指派"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"name_asc",label:"名称 升序"},{value:"name_desc",label:"名称 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建任务",type:"create",method:"post",path:"/tasks",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"任务名称"},executionID:{type:"integer",description:"所属执行",format:"int32"},type:{type:"string",description:"任务类型"},assignedTo:{type:"string",description:"指派给"},estStarted:{type:"string",description:"预计开始"},deadline:{type:"string",description:"截止日期"},pri:{type:"integer",description:"优先级",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},module:{type:"integer",description:"所属模块",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"},desc:{type:"string",description:"任务描述"}},required:["name","executionID"]}}},{name:"get",display:"获取任务详情",type:"get",method:"get",path:"/tasks/{taskID}",resultType:"object",pathParams:{taskID:"任务ID"}},{name:"update",display:"修改任务",type:"update",method:"put",path:"/tasks/{taskID}",resultType:"object",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"任务名称"},type:{type:"string",description:"任务类型"},assignedTo:{type:"string",description:"指派给"},estStarted:{type:"string",description:"预计开始"},deadline:{type:"string",description:"截止日期"},pri:{type:"integer",description:"优先级",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},module:{type:"integer",description:"所属模块",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"},desc:{type:"string",description:"任务描述"}}}}},{name:"delete",display:"删除任务",type:"delete",method:"delete",path:"/tasks/{taskID}",resultType:"text",pathParams:{taskID:"任务ID"},render:"action"},{name:"activate",display:"激活任务",type:"action",method:"put",path:"/tasks/{taskID}/activate",resultType:"text",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{left:{type:"number",description:"预计剩余",format:"float"},assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"close",display:"关闭任务",type:"action",method:"put",path:"/tasks/{taskID}/close",resultType:"text",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{comment:{type:"string",description:"备注"}}}},render:"action"},{name:"finish",display:"完成任务",type:"action",method:"put",path:"/tasks/{taskID}/finish",resultType:"text",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{currentConsumed:{type:"number",description:"本次消耗",format:"float"},assignedTo:{type:"string",description:"任务名称"},consumed:{type:"number",description:"总计消耗",format:"float"},realStarted:{type:"string",description:"实际开始"},finishedDate:{type:"string",description:"实际完成"},comment:{type:"string",description:"备注"}},required:["currentConsumed","realStarted","finishedDate"]}},render:"action"},{name:"start",display:"启动任务",type:"action",method:"put",path:"/tasks/{taskID}/start",resultType:"text",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"任务名称"},realStarted:{type:"string",description:"实际开始"},consumed:{type:"number",description:"总计消耗",format:"float"},left:{type:"number",description:"预计剩余",format:"float"},comment:{type:"string",description:"备注"}},required:["realStarted"]}},render:"action"}]},{name:"feedback",display:"反馈",description:"反馈管理,支持获取反馈列表,支持获取产品下的反馈、创建反馈、获取反馈详情、修改反馈、删除反馈、激活反馈、关闭反馈",actions:[{name:"list",display:"获取反馈列表,支持获取产品下的反馈",type:"list",method:"get",path:"/{scope}/{scopeID}/feedbacks",resultType:"list",pagerGetter:"pager",resultGetter:"feedbacks",pathParams:{scope:{description:"反馈范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是wait",defaultValue:"wait",options:[{value:"all",label:"全部"},{value:"wait",label:"待处理"},{value:"doing",label:"处理中"},{value:"toclosed",label:"待关闭"},{value:"review",label:"待评审"},{value:"assigntome",label:"指派给我"},{value:"openedbyme",label:"由我反馈"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建反馈",type:"create",method:"post",path:"/feedbacks",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{product:{type:"integer",description:"所属产品",format:"int32"},title:{type:"string",description:"标题"},module:{type:"integer",description:"所属模块",format:"int32"},type:{type:"string",description:"类型(story 需求 | task 任务 | bug Bug | todo 待办 | advice 建议 | issue 问题 | risk 风险 | opportunity 机会)"},desc:{type:"string",description:"描述"},feedbackBy:{type:"string",description:"反馈者"},source:{type:"string",description:"来源"}},required:["product","title"]}}},{name:"get",display:"获取反馈详情",type:"get",method:"get",path:"/feedbacks/{feedbackID}",resultType:"object",resultGetter:"feedback",pathParams:{feedbackID:"反馈ID"}},{name:"update",display:"修改反馈",type:"update",method:"put",path:"/feedbacks/{feedbackID}",resultType:"object",pathParams:{feedbackID:"反馈ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{product:{type:"integer",description:"所属产品",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},title:{type:"string",description:"标题"},type:{type:"string",description:"类型(story 需求 | task 任务 | bug Bug | todo 待办 | advice 建议 | issue 问题 | risk 风险 | opportunity 机会)"},desc:{type:"string",description:"描述"},feedbackBy:{type:"string",description:"反馈者"},source:{type:"string",description:"来源"}},required:["product","title"]}}},{name:"delete",display:"删除反馈",type:"delete",method:"delete",path:"/feedbacks/{feedbackID}",resultType:"text",pathParams:{feedbackID:"反馈ID"},render:"action"},{name:"activate",display:"激活反馈",type:"action",method:"put",path:"/feedbacks/{feedbackID}/activate",resultType:"text",pathParams:{feedbackID:"反馈ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"close",display:"关闭反馈",type:"action",method:"put",path:"/feedbacks/{feedbackID}/close",resultType:"text",pathParams:{feedbackID:"反馈ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(commented 已处理 | repeat 重复 | refuse 不予采纳)"},comment:{type:"string",description:"备注"}},required:["closedReason"]}},render:"action"}]},{name:"ticket",display:"工单",description:"工单管理,支持获取工单列表,支持获取产品下的工单、创建工单、获取工单详情、修改工单、删除工单、激活工单、关闭工单",actions:[{name:"list",display:"获取工单列表,支持获取产品下的工单",type:"list",method:"get",path:"/{scope}/{scopeID}/tickets",resultType:"list",pagerGetter:"pager",resultGetter:"tickets",pathParams:{scope:{description:"工单范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是wait",defaultValue:"wait",options:[{value:"all",label:"全部"},{value:"unclosed",label:"未关闭"},{value:"wait",label:"待处理"},{value:"doing",label:"处理中"},{value:"done",label:"待关闭"},{value:"finishedbyme",label:"由我解决"},{value:"assigntome",label:"指派给我"},{value:"openedbyme",label:"由我创建"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建工单",type:"create",method:"post",path:"/tickets",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{product:{type:"integer",description:"所属产品",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},title:{type:"string",description:"标题"},type:{type:"string",description:"类型(code 程序报错 | data 数据错误 | stuck 流程卡断 | security 安全问题 | affair 事务)"},desc:{type:"string",description:"描述"},assignedTo:{type:"string",description:"指派给"},deadline:{type:"string",description:"截止日期"},openedBuild:{type:"array",items:{type:"string"},description:"影响版本"}},required:["product","title"]}}},{name:"get",display:"获取工单详情",type:"get",method:"get",path:"/tickets/{ticketID}",resultType:"object",resultGetter:"ticket",pathParams:{ticketID:"工单ID"}},{name:"update",display:"修改工单",type:"update",method:"put",path:"/tickets/{ticketID}",resultType:"object",pathParams:{ticketID:"工单ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{product:{type:"integer",description:"所属产品",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},title:{type:"string",description:"标题"},type:{type:"string",description:"类型(code 程序报错 | data 数据错误 | stuck 流程卡断 | security 安全问题 | affair 事务)"},desc:{type:"string",description:"描述"},assignedTo:{type:"string",description:"指派给"},deadline:{type:"string",description:"截止日期"},openedBuild:{type:"array",items:{type:"string"},description:"影响版本"}}}}},{name:"delete",display:"删除工单",type:"delete",method:"delete",path:"/tickets/{ticketID}",resultType:"text",pathParams:{ticketID:"工单ID"},render:"action"},{name:"activate",display:"激活工单",type:"action",method:"put",path:"/tickets/{ticketID}/activate",resultType:"text",pathParams:{ticketID:"工单ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"close",display:"关闭工单",type:"action",method:"put",path:"/tickets/{ticketID}/close",resultType:"text",pathParams:{ticketID:"工单ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(commented 已处理 | repeat 重复 | refuse 不予处理)"},comment:{type:"string",description:"备注"}},required:["closedReason","comment"]}},render:"action"}]},{name:"system",display:"应用",description:"应用管理,支持获取应用列表,支持获取产品下的应用、创建应用、修改应用",actions:[{name:"list",display:"获取应用列表,支持获取产品下的应用",type:"list",method:"get",path:"/{scope}/{scopeID}/systems",resultType:"list",pagerGetter:"pager",pathParams:{scope:{description:"应用范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"}},{name:"create",display:"创建应用",type:"create",method:"post",path:"/systems",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品",format:"int32"},integrated:{type:"integer",description:"是否集成应用(0 否| 1 是)",format:"int32"},children:{type:"array",items:{type:"string"},description:"集成应用需要包含其他应用,非集成应用传空数组[]"},name:{type:"string",description:"应用名称"},desc:{type:"string",description:"描述"}},required:["productID","integrated","children","name"]}}},{name:"update",display:"修改应用",type:"update",method:"put",path:"/systems/{systemID}",resultType:"object",pathParams:{systemID:"应用ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"应用名称"},children:{type:"array",items:{type:"string"},description:"集成应用需要包含其他应用,非集成应用传空数组[]"},desc:{type:"string",description:"描述"}},required:["name","children"]}}}]},{name:"build",display:"版本",description:"版本管理,支持获取版本列表,支持获取项目/执行下的版本、创建版本/构建、修改版本、删除版本",actions:[{name:"list",display:"获取版本列表,支持获取项目/执行下的版本",type:"list",method:"get",path:"/{scope}/{scopeID}/builds",resultType:"list",pagerGetter:"pager",resultGetter:"builds",pathParams:{scope:{description:"版本范围",options:[{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"}},{name:"create",display:"创建版本/构建",type:"create",method:"post",path:"/builds",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{executionID:{type:"integer",description:"所属执行/迭代",format:"int32"},product:{type:"integer",description:"所属产品",format:"int32"},name:{type:"string",description:"构建名称"},system:{type:"integer",description:"所属应用",format:"int32"},builder:{type:"string",description:"构建者"},date:{type:"string",description:"打包日期"},scmPath:{type:"string",description:"源代码地址"},filePath:{type:"string",description:"下载地址"},desc:{type:"string",description:"描述"}},required:["executionID","product","name","system","builder","date"]}}},{name:"update",display:"修改版本",type:"update",method:"put",path:"/builds/{buildID}",resultType:"object",pathParams:{buildID:"版本ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{execution:{type:"integer",description:"所属执行/迭代",format:"int32"},product:{type:"integer",description:"所属产品",format:"int32"},name:{type:"string",description:"构建名称"},system:{type:"integer",description:"所属应用",format:"int32"},builder:{type:"string",description:"构建者"},date:{type:"string",description:"打包日期"},scmPath:{type:"string",description:"源代码地址"},filePath:{type:"string",description:"下载地址"},desc:{type:"string",description:"描述"}},required:["execution","product","name","system","builder","date"]}}},{name:"delete",display:"删除版本",type:"delete",method:"delete",path:"/builds/{buildID}",resultType:"text",pathParams:{buildID:"版本ID"},render:"action"}]},{name:"testtask",display:"测试单",description:"测试单管理,支持获取测试单列表,支持获取产品/项目/执行下的测试单、创建测试单、修改测试单、删除测试单",actions:[{name:"list",display:"获取测试单列表,支持获取产品/项目/执行下的测试单",type:"list",method:"get",path:"/{scope}/{scopeID}/testtasks",resultType:"list",pagerGetter:"pager",resultGetter:"testtasks",pathParams:{scope:{description:"测试单范围",options:[{value:"products",label:"产品"},{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"}},{name:"create",display:"创建测试单",type:"create",method:"post",path:"/testtasks",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品ID",format:"int32"},name:{type:"string",description:"测试单名称"},build:{type:"integer",description:"提测构建/版本",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"},type:{type:"array",items:{type:"string"},description:"类型(integrate 集成测试 | system 系统测试 | acceptance 验收测试 | performance 性能测试 | safety 安全测试)"},owner:{type:"string",description:"负责人"},status:{type:"string",description:"状态(wait 未开始 | doing 进行中 | done 已关闭 | blocked 被阻塞)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},desc:{type:"string",description:"描述"}},required:["productID","name","build","begin","end"]}}},{name:"update",display:"修改测试单",type:"update",method:"put",path:"/testtasks/{testtaskID}",resultType:"object",pathParams:{testtaskID:"测试单ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"测试单名称"},build:{type:"integer",description:"提测构建/版本",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"},type:{type:"array",items:{type:"string"},description:"类型(integrate 集成测试 | system 系统测试 | acceptance 验收测试 | performance 性能测试 | safety 安全测试)"},owner:{type:"string",description:"负责人"},status:{type:"string",description:"状态(wait 未开始 | doing 进行中 | done 已关闭 | blocked 被阻塞)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},desc:{type:"string",description:"描述"}},required:["name","build","begin","end"]}}},{name:"delete",display:"删除测试单",type:"delete",method:"delete",path:"/testtasks/{testtaskID}",resultType:"text",pathParams:{testtaskID:"测试单ID"},render:"action"}]},{name:"release",display:"发布",description:"发布管理,支持获取发布列表,支持获取产品下的发布、创建发布、修改发布、删除发布",actions:[{name:"list",display:"获取发布列表,支持获取产品下的发布",type:"list",method:"get",path:"/{scope}/{scopeID}/releases",resultType:"list",pagerGetter:"pager",resultGetter:"releases",pathParams:{scope:{description:"发布范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"}},{name:"create",display:"创建发布",type:"create",method:"post",path:"/releases",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品",format:"int32"},system:{type:"integer",description:"所属应用",format:"int32"},name:{type:"string",description:"应用版本号"},build:{type:"array",items:{type:"string"},description:"包含构建"},status:{type:"string",description:"状态(wait 未开始 | normal 已发布 | fail 发布失败 | terminate 停止维护)"},date:{type:"string",description:"计划发布日期"},desc:{type:"string",description:"描述"}},required:["productID","system","name","build","date"]}}},{name:"update",display:"修改发布",type:"update",method:"put",path:"/releases/{releasID}",resultType:"object",pathParams:{releasID:"发布ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{system:{type:"integer",description:"所属应用",format:"int32"},name:{type:"string",description:"应用版本号"},build:{type:"array",items:{type:"string"},description:"包含构建"},status:{type:"string",description:"状态(wait 未开始 | normal 已发布 | fail 发布失败 | terminate 停止维护)"},date:{type:"string",description:"计划发布日期"},desc:{type:"string",description:"描述"}},required:["system","name","build","date"]}}},{name:"delete",display:"删除发布",type:"delete",method:"delete",path:"/releases/{releasID}",resultType:"text",pathParams:{releasID:"发布ID"},render:"action"}]},{name:"file",display:"附件",description:"附件管理,支持编辑附件,修改附件的名称、删除附件",actions:[{name:"create",display:"编辑附件,修改附件的名称",type:"create",method:"post",path:"/files",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{fileName:{type:"string",description:"附件名称"}},required:["fileName"]}}},{name:"delete",display:"删除附件",type:"delete",method:"delete",path:"/files/{fileID}",resultType:"text",pathParams:{fileID:"附件ID"},render:"action"}]}];var K=uQ(U(KQ)),t=OQ(K);function U(Q){if(Array.isArray(Q))return Q.map((X)=>U(X));if(Q&&typeof Q==="object"&&!(Q instanceof Function)){let X={};for(let[$,J]of Object.entries(Q))X[$]=U(J);return X}return Q}function o(Q){if(Q===null||typeof Q!=="object")return Q;if(Object.isFrozen(Q))return Q;for(let X of Object.keys(Q))o(Q[X]);return Object.freeze(Q)}function a(Q){return o(Q)}function E(Q){return Q.actions.forEach(a),o(Q)}function uQ(Q){return Q.forEach(E),Q}function UQ(Q,X){let $=X.toLowerCase();return Q.findIndex((J)=>String(J.name).toLowerCase()===$)}function nQ(Q,X){let $=Q.slice();for(let J of X){let W=UQ($,String(J.name)),G=a(U(J));if(W>=0)$[W]=G;else $.push(G)}return $}function iQ(Q,X){return E({...Q,...U(X),actions:nQ(Q.actions,X.actions)})}function OQ(Q){return new Map(Q.map((X)=>[X.name.toLowerCase(),X]))}function TQ(){t=OQ(K)}function sQ(Q){if(!Q||typeof Q.name!=="string"||!Array.isArray(Q.actions))throw new H("E_INVALID_MODULE_DEFINITION")}function lQ(Q){if(!Q||typeof Q.name!=="string"||typeof Q.path!=="string"||typeof Q.method!=="string")throw new H("E_INVALID_ACTION_DEFINITION")}function r(Q,X={}){for(let $ of m(Q)){sQ($);let J=$.name.toLowerCase(),W=K.findIndex((G)=>G.name.toLowerCase()===J);if(W>=0)K[W]=X.replace?E(U($)):iQ(K[W],$);else K.push(E(U($)))}TQ()}function e(Q,X){let $=Q.toLowerCase(),J=t.get($);if(!J)throw new H("E_INVALID_MODULE",{module:Q});let W=J.actions.slice();for(let B of m(X)){lQ(B);let D=UQ(W,String(B.name)),M=a(U(B));if(D>=0)W[D]=M;else W.push(M)}let G=E({...J,actions:W}),q=K.findIndex((B)=>B.name.toLowerCase()===$);K[q]=G,TQ()}function j(Q){let X=t.get(Q.toLowerCase());if(!X)throw new H("E_INVALID_MODULE",{module:Q});return X}function N(Q,X){let $=j(Q),J=X==="ls"?"list":X,W=$.actions.find((q)=>String(q.name).toLowerCase()===J.toLowerCase());if(W)return W;if(!new Set(["list","get","create","update","delete"]).has(J)){let q=$.actions.find((B)=>B.type==="action"&&String(B.name).toLowerCase()===J.toLowerCase());if(q)return q}throw new H("E_INVALID_ACTION",{module:Q,action:X})}var tQ={product:"products",project:"projects",execution:"executions"},oQ=["execution","project","product"];function aQ(Q){for(let X of oQ){let $=Q[X]??Q[`${X}ID`];if($===void 0||$===null||$==="")continue;let J=Number($);if(!Number.isNaN(J))return{scope:tQ[X],scopeID:J}}return}function rQ(Q,X){return Q.path.replace(/\{(\w+)\}/g,($,J)=>{let W=X[J];if(W===void 0||W==="")throw new H("E_MISSING_PARAM",{param:J});return String(W)})}function eQ(Q){if(Q===void 0)return;if(typeof Q==="string")try{let X=JSON.parse(Q);return X&&typeof X==="object"&&!Array.isArray(X)?X:void 0}catch{return}return Q&&typeof Q==="object"&&!Array.isArray(Q)?Q:void 0}var QX=new Set(["true","1","yes","on"]),XX=new Set(["false","0","no","off"]);function $X(Q,X,$){if(Q===void 0||Q===null)return Q;if(X==="number"||X==="integer"){let J=Number(Q);return Number.isNaN(J)?Q:J}if(X==="boolean"){if(typeof Q==="boolean")return Q;if(typeof Q==="number"){if(Q===1)return!0;if(Q===0)return!1;throw new H("E_INVALID_PARAM",{param:$,value:String(Q)})}if(typeof Q==="string"){let J=Q.trim().toLowerCase();if(QX.has(J))return!0;if(XX.has(J))return!1;throw new H("E_INVALID_PARAM",{param:$,value:Q})}throw new H("E_INVALID_PARAM",{param:$,value:String(Q)})}return Q}function jQ(Q,X,$={}){let J=N(Q.name,X),W={},G=Object.keys(J.pathParams??{});if(G.includes("scope")){let Y=aQ($);if(!Y)throw new H("E_MISSING_PARAM",{param:"product/project/execution"});W.scope=Y.scope,W.scopeID=Y.scopeID}let q=G.find((Y)=>Y.endsWith("ID")&&Y!=="scopeID"),B=$.id??$[`${Q.name}ID`]??(q?$[q]:void 0),D=B===void 0?void 0:Number(B);if(q&&D!==void 0&&!Number.isNaN(D))W[q]=D;for(let Y of G){if(Y==="scope"||Y==="scopeID"||W[Y]!==void 0)continue;let A=J.pathParams?.[Y],L=$[Y];if(L!==void 0){W[Y]=L;continue}if(typeof A==="object"){if(A.defaultValue!==void 0)W[Y]=A.defaultValue;else if(A.options?.[0]?.value!==void 0)W[Y]=A.options[0].value}if(W[Y]===void 0)throw new H("E_MISSING_PARAM",{param:Y})}let M={};for(let Y of J.params??[]){let A=$[Y.name];if(A===void 0&&Y.name==="pageID")A=$.page;if(A===void 0)A=Y.defaultValue??Y.options?.[0]?.value;if(A===void 0&&Y.required)throw new H("E_MISSING_PARAM",{param:Y.name});if(A!==void 0)M[Y.name]=A}let C=eQ($.data);if(J.requestBody?.schema?.type==="object"){C=C?{...C}:{};let Y=J.requestBody.schema,A=new Set(Y.required??[]);for(let[L,O]of Object.entries(Y.properties??{})){let WQ=Object.prototype.hasOwnProperty.call(C,L),_Q=Object.prototype.hasOwnProperty.call($,L),F=WQ?C[L]:_Q?$[L]:O.defaultValue;if(F===void 0&&(O.required||A.has(L)))throw new H("E_MISSING_PARAM",{param:L});if(F=$X(F,O.type,L),O.type==="array"&&F!==void 0&&F!==null&&!Array.isArray(F)){if(typeof F==="string")F=F.split(",");else if(!WQ||!w(F))F=[F]}if(F!==void 0)C[L]=F}}return{module:Q.name,action:J,params:$,path:rQ(J,W),query:M,data:C,id:D===void 0||Number.isNaN(D)?void 0:D}}function IQ(Q,X){let $=Q.resultGetter;if(!$)return X.data??X;if(typeof $==="function")return $(X,{});if(typeof $==="string")return c(X,$);let J={};for(let[W,G]of Object.entries($))J[W]=X[G];return J}function wQ(Q,X){let $=Q.pagerGetter;if(!$)return X.pager;if(typeof $==="function")return $(X,{});if(typeof $==="string")return c(X,$);let J=X[$.pageID],W=X[$.recPerPage],G=X[$.recTotal];if(J===void 0||W===void 0||G===void 0)return;return{pageID:Number(J),recPerPage:Number(W),recTotal:Number(G)}}function JX(Q){let X=Q.indexOf("/");if(X<=0||X===Q.length-1)throw new H("E_INVALID_REQUEST_NAME");return{moduleName:Q.slice(0,X),actionName:Q.slice(X+1)}}function WX(Q,X,$){if(!X||typeof X!=="object"||Array.isArray(X))return{status:"success",data:X};let J=X,W=J.status==="fail"?"fail":"success",G=IQ(Q.action,J),q=$===void 0?void 0:Number($);if(Array.isArray(G)&&q!==void 0&&!Number.isNaN(q))G=G.slice(0,q);let B=wQ(Q.action,J);return{status:W,message:typeof J.message==="string"?J.message:void 0,data:G,pager:B?{total:Number(B.recTotal),page:Number(B.pageID),recPerPage:Number(B.recPerPage)}:void 0}}async function QQ(Q,X={},$={}){let J=R(),W=$.client??J.client;if(!W)throw new H("E_NO_GLOBAL_CLIENT");let{moduleName:G,actionName:q}=JX(Q),B=j(G),D=X.recPerPage??$.recPerPage??J.recPerPage,M=D===void 0?X:{...X,recPerPage:D},C=jQ(B,q,M),Y=await W.request(C.path,{method:String(C.action.method).toUpperCase(),query:C.query,body:C.data,timeout:$.timeout??J.timeout,insecure:$.insecure??J.insecure}),A=WX(C,Y,$.limit??J.limit);if(A.status==="fail"&&($.throwOnFail??J.throwOnFail))throw new H("E_API_FAILED",{message:A.message??""},A);return A}var XQ="2026-05-25T12:42:48.013Z",$Q="0.2.0";var JQ=globalThis;JQ.ZentaoAPI=b;if(JQ.window)JQ.window.ZentaoAPI=b;})();
1
+ (()=>{var{defineProperty:l,getOwnPropertyNames:fQ,getOwnPropertyDescriptor:vQ}=Object,cQ=Object.prototype.hasOwnProperty;function mQ(Q){return this[Q]}var dQ=(Q)=>{var X=(RQ??=new WeakMap).get(Q),$;if(X)return X;if(X=l({},"__esModule",{value:!0}),Q&&typeof Q==="object"||typeof Q==="function"){for(var J of fQ(Q))if(!cQ.call(X,J))l(X,J,{get:mQ.bind(Q,J),enumerable:!($=vQ(Q,J))||$.enumerable})}return RQ.set(Q,X),X},RQ;var uQ=(Q)=>Q;function pQ(Q,X){this[Q]=uQ.bind(null,X)}var UQ=(Q,X)=>{for(var $ in X)l(Q,$,{get:X[$],enumerable:!0,configurable:!0,set:pQ.bind(X,$)})};var zX={};UQ(zX,{switchProfile:()=>v,sortData:()=>g,setGlobalOptions:()=>w,searchData:()=>k,request:()=>qQ,processData:()=>F,pickFieldsSingle:()=>x,pickFields:()=>E,getProfileKey:()=>O,getProfile:()=>XQ,getModuleNames:()=>BQ,getModuleAction:()=>m,getModule:()=>S,getGlobalOptions:()=>j,getAllProfiles:()=>QQ,filterData:()=>N,deleteProfile:()=>$Q,defineModules:()=>YQ,defineModuleActions:()=>HQ,addProfile:()=>f,ZentaoError:()=>B,ZentaoClient:()=>_,ZENTAO_PROFILES_STORAGE_KEY:()=>b,VERSION:()=>GQ,ERRORS:()=>d,BUILD:()=>AQ});var i={};UQ(i,{switchProfile:()=>v,sortData:()=>g,setGlobalOptions:()=>w,searchData:()=>k,request:()=>qQ,processData:()=>F,pickFieldsSingle:()=>x,pickFields:()=>E,getProfileKey:()=>O,getProfile:()=>XQ,getModuleNames:()=>BQ,getModuleAction:()=>m,getModule:()=>S,getGlobalOptions:()=>j,getAllProfiles:()=>QQ,filterData:()=>N,deleteProfile:()=>$Q,defineModules:()=>YQ,defineModuleActions:()=>HQ,addProfile:()=>f,ZentaoError:()=>B,ZentaoClient:()=>_,ZENTAO_PROFILES_STORAGE_KEY:()=>b,VERSION:()=>GQ,ERRORS:()=>d,BUILD:()=>AQ});var d={E_INVALID_BASE_URL:"Invalid ZenTao baseUrl.",E_NO_GLOBAL_CLIENT:"No global client configured. Call ZentaoClient.init() or pass options.client.",E_HTTP_ERROR:"HTTP request failed: {status} {statusText}",E_NETWORK_ERROR:"Network request failed: {message}",E_TIMEOUT:"Request timed out.",E_INSECURE_BROWSER:"The insecure option is only supported in Node.js runtimes.",E_LOGIN_FAILED:"ZenTao login failed.",E_INVALID_PROFILE:"Invalid ZenTao profile.",E_NO_PROFILE:"No ZenTao profile is configured.",E_PROFILE_NOT_FOUND:"ZenTao profile not found: {profileKey}",E_PROFILE_STORAGE_INVALID:"ZenTao profile storage is not valid JSON.",E_PROFILE_STORAGE_UNAVAILABLE:"ZenTao profile storage is unavailable in this runtime.",E_INVALID_MODULE:"Unknown module: {module}",E_INVALID_ACTION:"Unknown action: {module}-{action}",E_INVALID_MODULE_DEFINITION:"Invalid module definition.",E_INVALID_ACTION_DEFINITION:"Invalid module action definition.",E_MISSING_PARAM:"Missing required parameter: {param}",E_INVALID_PARAM:"Invalid value for parameter {param}: {value}",E_INVALID_REQUEST_NAME:'Request name must use the form "moduleName/methodName".',E_API_FAILED:"ZenTao API returned failure: {message}"};class B extends Error{code;details;constructor(Q,X,$){let J=d[Q];if(X)for(let[W,D]of Object.entries(X))J=J.replaceAll(`{${W}}`,String(D));super(J);this.name="ZentaoError",this.code=Q,this.details=$}}function u(){return typeof process<"u"&&Boolean(process.versions?.node)}function KQ(Q){return import(Q)}function nQ(Q){let X={};return new Headers(Q).forEach(($,J)=>{X[J]=$}),X}function iQ(Q){let X=new Headers;for(let[$,J]of Object.entries(Q)){if(J===void 0)continue;X.set($,Array.isArray(J)?J.join(", "):String(J))}return X}async function lQ(Q){if(Q===void 0||Q===null)return;if(typeof Q==="string")return Q;if(Q instanceof Uint8Array)return Q;if(Q instanceof ArrayBuffer)return new Uint8Array(Q);if(ArrayBuffer.isView(Q))return new Uint8Array(Q.buffer,Q.byteOffset,Q.byteLength);if(Q instanceof Blob)return new Uint8Array(await Q.arrayBuffer());return String(Q)}function LQ(){return new DOMException("The operation was aborted.","AbortError")}function sQ(Q){let X=Q.reduce((W,D)=>W+D.byteLength,0),$=new Uint8Array(X),J=0;for(let W of Q)$.set(W,J),J+=W.byteLength;return $.buffer}async function tQ(Q,X,$){let J=new URL(Q),W=J.protocol==="https:"?await KQ("node:https"):await KQ("node:http"),D=await lQ(X.body);return new Promise((H,q)=>{if(X.signal?.aborted){q(LQ());return}let A=W.request(J,{method:X.method??"GET",headers:nQ(X.headers),rejectUnauthorized:$},(Y)=>{let G=[];Y.on("data",(C)=>{G.push(typeof C==="string"?new TextEncoder().encode(C):C)}),Y.on("end",()=>{M();let C=G.length>0?sQ(G):void 0,K=new Response(C,{status:Y.statusCode??200,statusText:Y.statusMessage??"",headers:iQ(Y.headers)});Object.defineProperty(K,"url",{value:Q}),H(K)})}),M=()=>{X.signal?.removeEventListener("abort",R)},R=()=>{M(),A.destroy(LQ())};if(A.on("error",(Y)=>{M(),q(Y)}),X.signal?.addEventListener("abort",R,{once:!0}),D!==void 0)A.write(D);A.end()})}function s(Q){if(Q&&!u())throw new B("E_INSECURE_BROWSER")}async function TQ(Q,X,$){if(!Q)return fetch(X,$);return s(Q),tQ(X,$,!1)}var t={};function j(){return{...t}}function w(Q){t={...t,...Q}}function L(Q){return Boolean(Q)&&typeof Q==="object"&&!Array.isArray(Q)}function T(Q,X){let $=X.split("."),J=Q;for(let W of $){if(J===null||J===void 0||typeof J!=="object")return;J=J[W]}return J}function I(Q){return Array.isArray(Q)?Q:[Q]}function z(Q){let X=Q.trim().replace(/\/+$/,"");if(!X)throw new B("E_INVALID_BASE_URL");let $=X.replace(/\/api\.php\/v2$/i,""),J;try{J=new URL($)}catch{throw new B("E_INVALID_BASE_URL")}if(!["http:","https:"].includes(J.protocol)||J.search||J.hash)throw new B("E_INVALID_BASE_URL");return J.toString().replace(/\/+$/,"")}function x(Q,X){let $={};for(let J of X){let W=T(Q,J);if(W===void 0)continue;let D=J.split("."),H=$;for(let q=0;q<D.length-1;q++){let A=D[q];if(!L(H[A]))H[A]={};H=H[A]}H[D[D.length-1]]=W}return $}function E(Q,X){return Q.map(($)=>x($,X))}function P(Q,X){let $=Number(Q),J=Number(X);if(Q!==""&&X!==""&&!Number.isNaN($)&&!Number.isNaN(J))return $-J;return String(Q).localeCompare(String(X))}function OQ(Q,X){let $=Number(Q),J=Number(X);if(Q!==""&&X!==""&&!Number.isNaN($)&&!Number.isNaN(J))return $===J;return String(Q)===String(X)}function VQ(Q,X){if(Q===void 0||Q===null)return!1;let $=String(Q).toLowerCase();return I(X).some((J)=>$.includes(String(J).toLowerCase()))}function jQ(Q,X){let $=T(Q,X.key),{operator:J,value:W}=X;switch(J){case"=":return I(W).some((D)=>OQ($,D));case"!=":return I(W).every((D)=>!OQ($,D));case"~":return VQ($,W);case"!~":return!VQ($,W);case">":return P($,W)>0;case"<":return P($,W)<0;case">=":return P($,W)>=0;case"<=":return P($,W)<=0;default:return!1}}function rQ(Q,X){if(X.conditions.length===0)return!0;return X.operator==="OR"?X.conditions.some(($)=>jQ(Q,$)):X.conditions.every(($)=>jQ(Q,$))}function N(Q,X){if(X.length===0)return Q.slice();return Q.filter(($)=>X.every((J)=>rQ($,J)))}function p(Q,X){if(Q===null||Q===void 0)return;if(Array.isArray(Q))for(let $ of Q)p($,X);else if(L(Q))for(let $ of Object.values(Q))p($,X);else X.push(String(Q))}function oQ(Q,X){let $=[];if(X&&X.length>0)for(let J of X)p(T(Q,J),$);else p(Q,$);return $.join("\x00").toLowerCase()}function k(Q,X,$){let J=X.map((W)=>W.toLowerCase().split(/\s+/).filter(Boolean)).filter((W)=>W.length>0);if(J.length===0)return Q.slice();return Q.filter((W)=>{let D=oQ(W,$);return J.every((H)=>H.some((q)=>D.includes(q)))})}function aQ(Q){if(typeof Q==="function")return Q;let X=Q.lastIndexOf(":"),$=X>=0?Q.slice(0,X):Q,W=(X>=0?Q.slice(X+1):"asc")==="desc"?-1:1;return(D,H)=>P(T(D,$),T(H,$))*W}function g(Q,X){let $=X.map(aQ);return Q.slice().sort((J,W)=>{for(let D of $){let H=D(J,W);if(H!==0)return H}return 0})}var eQ=[">=","<=","!=","!~","=","~",">","<"];function QX(Q){if(Q.startsWith("[")&&Q.endsWith("]"))return Q.slice(1,-1).split(",").map((X)=>X.trim()).filter(Boolean);if(Q==="true")return!0;if(Q==="false")return!1;if(Q!==""&&!Number.isNaN(Number(Q)))return Number(Q);return Q}function XX(Q){for(let X of eQ){let $=Q.indexOf(X);if($>0)return{key:Q.slice(0,$).trim(),operator:X,value:QX(Q.slice($+X.length).trim())}}return}function $X(Q){if(Q===void 0||Q==="")return;let X=Number(Q);if(!Number.isFinite(X)||X<0)return;return Math.floor(X)}function F(Q,X){if(!Array.isArray(Q))return X.pick?x(Q,X.pick):{...Q};let $=X,J=Q;if($.filter&&$.filter.length>0){let D=$.filter.map(XX).filter((H)=>H!==void 0);if(D.length>0)J=N(J,[{operator:"AND",conditions:D}])}if($.search&&$.search.length>0)J=k(J,$.search,$.searchFields);if($.sort){let D=$.sort.split(",").map((H)=>H.trim()).filter(Boolean);if(D.length>0)J=g(J,D)}let W=$X($.limit);if(W!==void 0)J=J.slice(0,W);if($.pick)J=E(J,$.pick);return J}var b="ZENTAO_PROFILES",JX=[".config","zentao","zentao.json"];function FQ(Q){return Boolean(Q)&&typeof Q==="object"&&!Array.isArray(Q)}function _Q(Q){if(Q===void 0)return Q;return JSON.parse(JSON.stringify(Q))}function zQ(){return new Date().toISOString()}function h(Q){return import(Q)}var IQ=Promise.resolve();function r(Q){let X=IQ.then(Q,Q);return IQ=X.catch(()=>{return}),X}function xQ(){try{return globalThis.localStorage}catch{return}}async function SQ(){let Q=await h("node:path"),X=process.env.HOME??process.env.USERPROFILE??(await h("node:os")).homedir();if(!X)throw new B("E_PROFILE_STORAGE_UNAVAILABLE");return Q.join(X,...JX)}function WX(Q,X){let $=Q.trim(),J=z(X);if(!$)throw new B("E_INVALID_PROFILE");return`${$}@${J}`}function o(Q){if(!FQ(Q)||typeof Q.server!=="string"||typeof Q.account!=="string"||typeof Q.token!=="string")throw new B("E_INVALID_PROFILE");let X=Q.token.trim();if(!X)throw new B("E_INVALID_PROFILE");let $=_Q(Q);return delete $.key,{...$,server:z(Q.server),account:Q.account.trim(),token:X}}function wQ(Q){if(!FQ(Q))return{profiles:[]};let X=Array.isArray(Q.profiles)?Q.profiles.flatMap((J)=>{try{return[o(J)]}catch{return[]}}):[],$=typeof Q.currentProfile==="string"?Q.currentProfile:void 0;return $?{currentProfile:$,profiles:X}:{profiles:X}}function ZQ(Q){try{return wQ(JSON.parse(Q))}catch(X){throw new B("E_PROFILE_STORAGE_INVALID",void 0,X)}}async function y(){if(u()){let $=await h("node:fs/promises"),J=await SQ();try{return ZQ(await $.readFile(J,"utf8"))}catch(W){if(W.code==="ENOENT")return{profiles:[]};throw W}}let Q=xQ();if(!Q)throw new B("E_PROFILE_STORAGE_UNAVAILABLE");let X=Q.getItem(b);return X?ZQ(X):{profiles:[]}}async function a(Q){let X=wQ(Q),$=`${JSON.stringify(X,null,2)}
2
+ `;if(u()){let W=await h("node:fs/promises"),D=await h("node:path"),H=await SQ(),q=D.dirname(H),A=D.join(q,`.zentao.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`);await W.mkdir(q,{recursive:!0,mode:448}),await W.chmod(q,448).catch(()=>{return});try{await W.writeFile(A,$,{encoding:"utf8",mode:384}),await W.rename(A,H),await W.chmod(H,384).catch(()=>{return})}catch(M){throw await W.rm(A,{force:!0}).catch(()=>{return}),M}return}let J=xQ();if(!J)throw new B("E_PROFILE_STORAGE_UNAVAILABLE");J.setItem(b,$)}function n(Q){let X=o(Q);return{..._Q(X),key:O(X)}}function e(Q,X){return Q.profiles.find(($)=>O($)===X)}function DX(Q){if(!Q.currentProfile||!e(Q,Q.currentProfile)){let X=Q.profiles.at(-1);Q.currentProfile=X?O(X):void 0}}function O(Q){return WX(Q.account,Q.server)}async function QQ(){return(await y()).profiles.map(n)}async function XQ(Q){let X=await y(),$=Q??X.currentProfile;if(!$)return;let J=e(X,$);return J?n(J):void 0}function f(Q){return r(async()=>{let X=await y(),$=zQ(),J=o({...Q,loginTime:Q.loginTime??$,lastUsedTime:Q.lastUsedTime??$}),W=O(J),D=X.profiles.findIndex((H)=>O(H)===W);if(D>=0)X.profiles[D]=J;else X.profiles.push(J);return X.currentProfile=W,await a(X),n(J)})}function $Q(Q){return r(async()=>{let X=await y(),$=X.profiles.filter((J)=>O(J)!==Q);if($.length===X.profiles.length)return!1;return X.profiles=$,DX(X),await a(X),!0})}function v(Q){return r(async()=>{let X=await y(),$=Q??X.currentProfile;if(!$)throw new B("E_NO_PROFILE");let J=e(X,$);if(!J)throw new B("E_PROFILE_NOT_FOUND",{profileKey:$});return J.lastUsedTime=zQ(),X.currentProfile=$,await a(X),n(J)})}var YX=1e4;function HX(Q,X,$){let J=X.startsWith("/")?X:`/${X}`,W=new URL(`${Q}${J}`);for(let[D,H]of Object.entries($??{})){if(H===void 0)continue;W.searchParams.set(D,String(H))}return W.toString()}async function BX(Q){let X=await Q.text();if(X==="")return;try{return JSON.parse(X)}catch{return X}}class _{siteUrl;baseUrl;token;timeout;insecure;constructor(Q){let X=typeof Q==="string"?{baseUrl:Q}:Q;this.siteUrl=z(X.baseUrl),this.baseUrl=`${this.siteUrl}/api.php/v2`,this.token=X.token,this.timeout=X.timeout,this.insecure=X.insecure}async request(Q,X={}){let $=j(),J=X.method??"GET",W=X.timeout??$.timeout??this.timeout??YX,D=X.insecure??$.insecure??this.insecure;s(D);let H=HX(this.baseUrl,Q,X.query),q=new AbortController,A=setTimeout(()=>q.abort(),W),M={};if(this.token)M.Token=this.token;let R={method:J,headers:M,signal:q.signal};if(X.body!==void 0&&J!=="GET")M["Content-Type"]="application/json",R.body=JSON.stringify(X.body);try{let Y=await TQ(D,H,R);if(!Y.ok)throw new B("E_HTTP_ERROR",{status:Y.status,statusText:Y.statusText},{url:Y.url,status:Y.status,statusText:Y.statusText,body:await Y.text().catch(()=>{return})});return BX(Y)}catch(Y){if(Y instanceof B)throw Y;if(Y instanceof DOMException&&Y.name==="AbortError")throw new B("E_TIMEOUT");throw new B("E_NETWORK_ERROR",{message:Y.message??String(Y)},Y)}finally{clearTimeout(A)}}async get(Q){return this.request(Q,{method:"GET"})}async post(Q,X){return this.request(Q,{method:"POST",body:X})}async put(Q,X){return this.request(Q,{method:"PUT",body:X})}async delete(Q){return this.request(Q,{method:"DELETE"})}async login(Q,X){let $=await this.post("/users/login",{account:Q,password:X});if($.status!=="success"||!$.token)throw new B("E_LOGIN_FAILED");this.token=$.token;let J=j();if(J.persistProfiles){let W={},D=this.timeout??J.timeout,H=this.insecure??J.insecure;if(D!==void 0)W.timeout=D;if(H!==void 0)W.insecure=H;await f({server:this.siteUrl,account:Q,token:$.token,user:L($.user)?$.user:void 0,serverConfig:L($.serverConfig)?$.serverConfig:void 0,config:Object.keys(W).length>0?W:void 0})}return $.token}static create(Q){return new _(Q)}static init(Q){let X=new _(Q);return w({client:X}),X}static async fromProfile(Q){let X=await v(Q);return new _({baseUrl:X.server,token:X.token,timeout:typeof X.config?.timeout==="number"?X.config.timeout:void 0,insecure:typeof X.config?.insecure==="boolean"?X.config.insecure:void 0})}}var PQ=[{name:"user",display:"用户",description:"用户管理,支持获取用户列表、创建用户、获取用户详情、修改用户信息、删除用户",actions:[{name:"list",display:"获取用户列表",type:"list",method:"get",path:"/users",resultType:"list",pagerGetter:"pager",resultGetter:"users",params:[{name:"browseType",required:!1,type:"string",description:"浏览类型",options:[{value:"inside",label:"内部用户"},{value:"outside",label:"内部用户"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"realname_asc",label:"姓名 升序"},{value:"realname_desc",label:"姓名 降序"},{value:"account_asc",label:"用户名 升序"},{value:"account_desc",label:"用户名 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建用户",type:"create",method:"post",path:"/users",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{account:{type:"string",description:"登录名"},realname:{type:"string",description:"姓名"},password:{type:"string",description:"密码"}},required:["account","realname","password"]}}},{name:"get",display:"获取用户详情",type:"get",method:"get",path:"/users/{userID}",resultType:"object",resultGetter:"user",pathParams:{userID:"用户ID"}},{name:"update",display:"修改用户信息",type:"update",method:"put",path:"/users/{userID}",resultType:"object",pathParams:{userID:"用户ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{realname:{type:"string",description:"真实姓名"},dept:{type:"integer",description:"部门",format:"int32"},join:{type:"string",description:"入职日期"},group:{type:"array",items:{type:"string"},description:"权限分组"},email:{type:"string",description:"邮箱"},visions:{type:"array",items:{type:"string"},description:"界面类型(研发综合界面 rnd | 运营管理界面 lite)"},mobile:{type:"string",description:"手机"},weixin:{type:"string",description:"微信"},password:{type:"string",description:"密码"}}}}},{name:"delete",display:"删除用户",type:"delete",method:"delete",path:"/users/{userID}",resultType:"text",pathParams:{userID:"用户ID"},render:"action"}]},{name:"program",display:"项目集",description:"项目集管理,支持获取项目集列表、创建项目集、获取项目集详情、修改项目集、删除项目集",actions:[{name:"list",display:"获取项目集列表",type:"list",method:"get",path:"/programs",resultType:"list",pagerGetter:"pager",resultGetter:"programs",params:[{name:"status",required:!1,type:"string",description:"状态",options:[{value:"all",label:"全部"},{value:"unclosed",label:"未关闭"},{value:"wait",label:"未开始"},{value:"doing",label:"进行中"},{value:"suspended",label:"已挂起"},{value:"delayed",label:"已延期"},{value:"closed",label:"已关闭"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"name_asc",label:"名称 升序"},{value:"name_desc",label:"名称 降序"},{value:"begin_asc",label:"计划开始 升序"},{value:"begin_desc",label:"计划开始 降序"},{value:"end_asc",label:"计划结束 升序"},{value:"end_desc",label:"计划结束 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建项目集",type:"create",method:"post",path:"/programs",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"项目集名称"},begin:{type:"string",description:"计划开始日期"},end:{type:"string",description:"计划完成日期"},PM:{type:"string",description:"计划完成日期"},desc:{type:"string",description:"项目集描述"}},required:["name","begin","end"]}}},{name:"get",display:"获取项目集详情",type:"get",method:"get",path:"/programs/{programID}",resultType:"object",resultGetter:"program",pathParams:{programID:"项目集ID"}},{name:"update",display:"修改项目集",type:"update",method:"put",path:"/programs/{programID}",resultType:"object",pathParams:{programID:"项目集ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"项目集名称"},begin:{type:"string",description:"计划开始日期"},end:{type:"string",description:"计划完成日期"},PM:{type:"string",description:"计划完成日期"},desc:{type:"string",description:"项目集描述"}},required:["name","begin","end"]}}},{name:"delete",display:"删除项目集",type:"delete",method:"delete",path:"/programs/{programID}",resultType:"text",pathParams:{programID:"项目集ID"},render:"action"}]},{name:"product",display:"产品",description:"产品管理,支持获取产品列表、创建产品、获取产品详情、修改产品、删除产品",actions:[{name:"list",display:"获取产品列表",type:"list",method:"get",path:"/products",resultType:"list",pagerGetter:"pager",resultGetter:"products",params:[{name:"browseType",required:!1,type:"string",description:"浏览类型",options:[{value:"all",label:"全部"},{value:"noclosed",label:"未关闭"},{value:"closed",label:"已结束"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"名称 升序"},{value:"title_desc",label:"名称 降序"},{value:"begin_asc",label:"计划开始 升序"},{value:"begin_desc",label:"计划开始 降序"},{value:"end_asc",label:"计划结束 升序"},{value:"end_desc",label:"计划结束 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建产品",type:"create",method:"post",path:"/products",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"产品名称"},program:{type:"integer",description:"所属项目集",format:"int32"},line:{type:"integer",description:"所属产品线",format:"int32"},type:{type:"string",description:"类型(normal 正常 | branch 多分支 | platform 多平台)"},PO:{type:"string",description:"产品负责人"},reviewer:{type:"array",items:{type:"string"},description:"评审人"},desc:{type:"array",items:{type:"string"},description:"产品描述"},QD:{type:"string",description:"测试负责人"},RD:{type:"string",description:"发布负责人"},acl:{type:"string",description:"访问控制(open 公开 | private 私有)"}},required:["name"]}}},{name:"get",display:"获取产品详情",type:"get",method:"get",path:"/products/{productID}",resultType:"object",resultGetter:"product",pathParams:{productID:"产品ID"}},{name:"update",display:"修改产品",type:"update",method:"put",path:"/products/{productID}",resultType:"object",pathParams:{productID:"产品ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"产品名称"},program:{type:"integer",description:"所属项目集",format:"int32"},line:{type:"integer",description:"所属产品线",format:"int32"},type:{type:"string",description:"类型(normal 正常 | branch 多分支 | platform 多平台)"},PO:{type:"string",description:"产品负责人"},reviewer:{type:"array",items:{type:"string"},description:"评审人"},desc:{type:"array",items:{type:"string"},description:"产品描述"},QD:{type:"string",description:"测试负责人"},RD:{type:"string",description:"发布负责人"},acl:{type:"string",description:"访问控制(open 公开 | private 私有)"}},required:["name"]}}},{name:"delete",display:"删除产品",type:"delete",method:"delete",path:"/products/{productID}",resultType:"text",pathParams:{productID:"产品ID"},render:"action"}]},{name:"project",display:"项目",description:"项目管理,支持获取项目列表、创建项目、修改项目、删除项目",actions:[{name:"list",display:"获取项目列表",type:"list",method:"get",path:"/projects",resultType:"list",pagerGetter:"pager",resultGetter:"projects",params:[{name:"browseType",required:!1,type:"string",description:"项目状态,默认是undone",defaultValue:"undone",options:[{value:"all",label:"全部"},{value:"undone",label:"未完成"},{value:"wait",label:"未开始"},{value:"doing",label:"进行中"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"name_asc",label:"名称 升序"},{value:"name_desc",label:"名称 降序"},{value:"begin_asc",label:"计划开始 升序"},{value:"begin_desc",label:"计划开始 降序"},{value:"end_asc",label:"计划结束 升序"},{value:"end_desc",label:"计划结束 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建项目",type:"create",method:"post",path:"/projects",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"项目名称"},model:{type:"string",description:"项目管理方式(scrum 敏捷 | waterfall 瀑布 | kanban 看板 | agileplus 融合敏捷 | waterfallplus 融合瀑布)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},products:{type:"array",items:{type:"string"},description:"关联产品"},parent:{type:"integer",description:"所属项目集",format:"int32"},workflowGroup:{type:"integer",description:"项目流程,付费版功能,开源版可以不填",format:"int32"},PM:{type:"string",description:"项目负责人"}},required:["name","model","begin","end","workflowGroup"]}}},{name:"update",display:"修改项目",type:"update",method:"put",path:"/projects/{projectID}",resultType:"object",pathParams:{projectID:"项目ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"项目名称"},model:{type:"string",description:"项目管理方式(scrum 敏捷 | waterfall 瀑布 | kanban 看板 | agileplus 融合敏捷 | waterfallplus 融合瀑布)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},products:{type:"array",items:{type:"string"},description:"关联产品"},parent:{type:"integer",description:"所属项目集",format:"int32"},workflowGroup:{type:"integer",description:"项目流程,付费版功能,开源版可以不填",format:"int32"},PM:{type:"string",description:"项目负责人"}},required:["name","model","begin","end","workflowGroup"]}}},{name:"delete",display:"删除项目",type:"delete",method:"delete",path:"/projects/{projectID}",resultType:"text",pathParams:{projectID:"项目ID"},render:"action"}]},{name:"execution",display:"执行",description:"执行管理,支持获取执行列表、创建执行、获取执行详情、修改执行、删除执行",actions:[{name:"list",display:"获取执行列表",type:"list",method:"get",path:"/executions",resultType:"list",pagerGetter:"pager",resultGetter:"executions",params:[{name:"status",required:!1,type:"string",description:"执行状态,默认是undone",defaultValue:"undone",options:[{value:"all",label:"全部"},{value:"undone",label:"未完成"},{value:"wait",label:"未开始"},{value:"doing",label:"进行中"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"rawID_asc",label:"RAWID 升序"},{value:"rawID_desc",label:"RAWID 降序"},{value:"nameCol_asc",label:"名称 升序"},{value:"nameCol_desc",label:"名称 降序"},{value:"begin_asc",label:"计划开始 升序"},{value:"begin_desc",label:"计划开始 降序"},{value:"end_asc",label:"计划结束 升序"},{value:"end_desc",label:"计划结束 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建执行",type:"create",method:"post",path:"/executions",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{project:{type:"integer",description:"所属项目",format:"int32"},name:{type:"string",description:"迭代名称"},lifetime:{type:"string",description:"执行类型(short 短期 | long 长期 | ops 运维)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},days:{type:"integer",description:"可用工作日",format:"int32"},products:{type:"array",items:{type:"string"},description:"关联产品"},plans:{type:"array",items:{type:"string"},description:"关联计划,必须是产品+planID的二维数组"},PO:{type:"string",description:"产品负责人"},QD:{type:"string",description:"测试负责人"},PM:{type:"string",description:"执行负责人"},RD:{type:"string",description:"发布负责人"},acl:{type:"string",description:"访问控制(open 公开 | private 私有)"}},required:["project","name","begin","end"]}}},{name:"get",display:"获取执行详情",type:"get",method:"get",path:"/executions/{executionID}",resultType:"object",resultGetter:"execution",pathParams:{executionID:"执行ID"}},{name:"update",display:"修改执行",type:"update",method:"put",path:"/executions/{executionID}",resultType:"object",pathParams:{executionID:"执行ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{project:{type:"integer",description:"所属项目",format:"int32"},name:{type:"string",description:"迭代名称"},lifetime:{type:"string",description:"执行类型(short 短期 | long 长期 | ops 运维)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},days:{type:"integer",description:"可用工作日",format:"int32"},products:{type:"array",items:{type:"string"},description:"关联产品"},plans:{type:"array",items:{type:"string"},description:"关联计划,必须是产品+planID的二维数组"},PO:{type:"string",description:"产品负责人"},QD:{type:"string",description:"测试负责人"},PM:{type:"string",description:"执行负责人"},RD:{type:"string",description:"发布负责人"},acl:{type:"string",description:"访问控制(open 公开 | private 私有)"}},required:["name","begin","end"]}}},{name:"delete",display:"删除执行",type:"delete",method:"delete",path:"/executions/{executionID}",resultType:"text",pathParams:{executionID:"执行ID"},render:"action"}]},{name:"productplan",display:"产品计划",description:"产品计划管理,支持获取产品计划列表,支持获取产品下的产品计划、创建产品计划、获取产品计划详情、修改产品计划、删除产品计划",actions:[{name:"list",display:"获取产品计划列表,支持获取产品下的产品计划",type:"list",method:"get",path:"/{scope}/{scopeID}/productplans",resultType:"list",pagerGetter:"pager",resultGetter:"productplans",pathParams:{scope:{description:"产品计划范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"执行状态,默认是undone",defaultValue:"undone",options:[{value:"all",label:"全部"},{value:"undone",label:"未完成"},{value:"wait",label:"未开始"},{value:"doing",label:"进行中"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"名称 升序"},{value:"title_desc",label:"名称 降序"},{value:"begin_asc",label:"开始日期 升序"},{value:"begin_desc",label:"开始日期 降序"},{value:"end_asc",label:"结束日期 升序"},{value:"end_desc",label:"结束日期 降序"},{value:"status_asc",label:"状态 升序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建产品计划",type:"create",method:"post",path:"/productplans",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"产品ID",format:"int32"},title:{type:"string",description:"计划名称"},parent:{type:"integer",description:"父计划ID",format:"int32"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},branchID:{type:"integer",description:"分支ID",format:"int32"},desc:{type:"string",description:"计划描述"}},required:["productID","title"]}}},{name:"get",display:"获取产品计划详情",type:"get",method:"get",path:"/productplans/{planID}",resultType:"object",resultGetter:"productplan",pathParams:{planID:"产品计划ID"}},{name:"update",display:"修改产品计划",type:"update",method:"put",path:"/productplans/{productplanID}",resultType:"object",pathParams:{productplanID:"产品计划ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"计划名称"},parent:{type:"integer",description:"父计划",format:"int32"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},branchID:{type:"integer",description:"分支ID",format:"int32"},desc:{type:"string",description:"计划描述"}},required:["title"]}}},{name:"delete",display:"删除产品计划",type:"delete",method:"delete",path:"/productplans/{productplanID}",resultType:"text",pathParams:{productplanID:"产品计划ID"},render:"action"}]},{name:"story",display:"需求",description:"需求管理,支持获取需求列表,支持获取产品/项目/执行下的需求、创建需求、获取需求详情、修改需求、删除需求、激活需求、变更需求、关闭需求",actions:[{name:"list",display:"获取需求列表,支持获取产品/项目/执行下的需求",type:"list",method:"get",path:"/{scope}/{scopeID}/stories",resultType:"list",pagerGetter:"pager",resultGetter:"stories",pathParams:{scope:{description:"需求范围",options:[{value:"products",label:"产品"},{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"allstory",label:"全部"},{value:"assignedtome",label:"指派给我"},{value:"openedbyme",label:"我创建"},{value:"reviewbyme",label:"待我评审"},{value:"draftstory",label:"草稿"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建需求",type:"create",method:"post",path:"/stories",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"产品ID",format:"int32"},title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},spec:{type:"string",description:"需求描述"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},verify:{type:"string",description:"验收标准"},assignedTo:{type:"string",description:"指派给"},reviewer:{type:"array",items:{type:"string"},description:"评审人,如果设置必须评审,必须填写"},project:{type:"integer",description:"所属项目",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"}},required:["productID","title"]}}},{name:"get",display:"获取需求详情",type:"get",method:"get",path:"/stories/{storyID}",resultType:"object",resultGetter:"story",pathParams:{storyID:"需求ID"}},{name:"update",display:"修改需求",type:"update",method:"put",path:"/stories/{storyID}",resultType:"object",pathParams:{storyID:"需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},assignedTo:{type:"string",description:"指派给"}},required:["title"]}}},{name:"delete",display:"删除需求",type:"delete",method:"delete",path:"/stories/{storyID}",resultType:"text",pathParams:{storyID:"需求ID"},render:"action"},{name:"activate",display:"激活需求",type:"action",method:"put",path:"/stories/{storyID}/activate",resultType:"text",pathParams:{storyID:"需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"change",display:"变更需求",type:"action",method:"put",path:"/stories/{storyID}/change",resultType:"text",pathParams:{storyID:"需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"需求名称"},reviewer:{type:"array",items:{type:"string"},description:"评审人员"},spec:{type:"string",description:"需求描述"},verify:{type:"string",description:"验收标准"}},required:["reviewer"]}},render:"action"},{name:"close",display:"关闭需求",type:"action",method:"put",path:"/stories/{storyID}/close",resultType:"text",pathParams:{storyID:"需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(done 已完成 | subdivided 已拆分 | duplicate 重复 | postponed 延期 | willnotdo 不做 | cancel 已取消 | bydesign 设计如此)"},comment:{type:"string",description:"备注"}},required:["closedReason"]}},render:"action"}]},{name:"epic",display:"业务需求",description:"业务需求管理,支持获取业务需求列表,支持获取产品下的业务需求、创建业务需求、获取业务需求详情、修改业务需求、删除业务需求、激活业务需求、变更业务需求、关闭业务需求",actions:[{name:"list",display:"获取业务需求列表,支持获取产品下的业务需求",type:"list",method:"get",path:"/{scope}/{scopeID}/epics",resultType:"list",pagerGetter:"pager",resultGetter:"epics",pathParams:{scope:{description:"业务需求范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"allstory",label:"全部"},{value:"assignedtome",label:"指派给我"},{value:"openedbyme",label:"我创建"},{value:"reviewbyme",label:"待我评审"},{value:"draftstory",label:"草稿"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建业务需求",type:"create",method:"post",path:"/epics",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"产品ID",format:"int32"},title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父业务需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},spec:{type:"string",description:"业务需求描述"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},verify:{type:"string",description:"验收标准"},assignedTo:{type:"string",description:"指派给"},reviewer:{type:"array",items:{type:"string"},description:"评审人,如果设置必须评审,必须填写"}},required:["productID","title"]}}},{name:"get",display:"获取业务需求详情",type:"get",method:"get",path:"/epics/{storyID}",resultType:"object",resultGetter:"epic",pathParams:{storyID:"需求ID"}},{name:"update",display:"修改业务需求",type:"update",method:"put",path:"/epics/{epicID}",resultType:"object",pathParams:{epicID:"业务需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"需求名称"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父业务需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},assignedTo:{type:"string",description:"指派给"}},required:["title"]}}},{name:"delete",display:"删除业务需求",type:"delete",method:"delete",path:"/epics/{epicID}",resultType:"text",pathParams:{epicID:"业务需求ID"},render:"action"},{name:"activate",display:"激活业务需求",type:"action",method:"put",path:"/epics/{epicID}/activate",resultType:"text",pathParams:{epicID:"业务需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"change",display:"变更业务需求",type:"action",method:"put",path:"/epics/{epicID}/change",resultType:"text",pathParams:{epicID:"业务需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"需求名称"},reviewer:{type:"array",items:{type:"string"},description:"评审人员"},spec:{type:"string",description:"需求描述"},verify:{type:"string",description:"验收标准"}},required:["reviewer"]}},render:"action"},{name:"close",display:"关闭业务需求",type:"action",method:"put",path:"/epics/{epicID}/close",resultType:"text",pathParams:{epicID:"业务需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(done 已完成 | subdivided 已拆分 | duplicate 重复 | postponed 延期 | willnotdo 不做 | cancel 已取消 | bydesign 设计如此)"},comment:{type:"string",description:"备注"}},required:["closedReason"]}},render:"action"}]},{name:"requirement",display:"用户需求",description:"用户需求管理,支持获取用户需求列表,支持获取产品下的用户需求、创建用户需求、获取用户需求详情、修改用户需求、删除用户需求、激活用户需求、变更用户需求、关闭用户需求",actions:[{name:"list",display:"获取用户需求列表,支持获取产品下的用户需求",type:"list",method:"get",path:"/{scope}/{scopeID}/requirements",resultType:"list",pagerGetter:"pager",resultGetter:"requirements",pathParams:{scope:{description:"用户需求范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"allstory",label:"全部"},{value:"assignedtome",label:"指派给我"},{value:"openedbyme",label:"我创建"},{value:"reviewbyme",label:"待我评审"},{value:"draftstory",label:"草稿"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建用户需求",type:"create",method:"post",path:"/requirements",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"产品ID",format:"int32"},title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父用户需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},spec:{type:"string",description:"用户需求描述"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},verify:{type:"string",description:"验收标准"},assignedTo:{type:"string",description:"指派给"},reviewer:{type:"array",items:{type:"string"},description:"评审人,如果设置必须评审,必须填写"}},required:["productID","title"]}}},{name:"get",display:"获取用户需求详情",type:"get",method:"get",path:"/requirements/{storyID}",resultType:"object",resultGetter:"requirement",pathParams:{storyID:"需求ID"}},{name:"update",display:"修改用户需求",type:"update",method:"put",path:"/requirements/{requirementID}",resultType:"object",pathParams:{requirementID:"用户需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},parent:{type:"integer",description:"父用户需求",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},category:{type:"integer",description:"类别(feature 功能 | interface 接口 | performance 性能 | safe 安全 | experience 体验 | improve 改进 | other 其他)",format:"int32"},source:{type:"string",description:"来源(customer 客户 | user 用户 | po 产品经理 | market 市场 | service 客服 | operation 运营 | support 技术支持 | competitor 竞争对手 | partner 合作伙伴 | dev 开发人员 | tester 测试人员 | bug Bug | forum 论坛 | other 其他)"},assignedTo:{type:"string",description:"指派给"}},required:["title"]}}},{name:"delete",display:"删除用户需求",type:"delete",method:"delete",path:"/requirements/{requirementID}",resultType:"text",pathParams:{requirementID:"用户需求ID"},render:"action"},{name:"activate",display:"激活用户需求",type:"action",method:"put",path:"/requirements/{requirementID}/activate",resultType:"text",pathParams:{requirementID:"用户需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"change",display:"变更用户需求",type:"action",method:"put",path:"/requirements/{requirementID}/change",resultType:"text",pathParams:{requirementID:"用户需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"需求名称"},spec:{type:"string",description:"需求描述"},verify:{type:"string",description:"验收标准"}}}},render:"action"},{name:"close",display:"关闭用户需求",type:"action",method:"put",path:"/requirements/{requirementID}/close",resultType:"text",pathParams:{requirementID:"用户需求ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(done 已完成 | subdivided 已拆分 | duplicate 重复 | postponed 延期 | willnotdo 不做 | cancel 已取消 | bydesign 设计如此)"},comment:{type:"string",description:"备注"}},required:["closedReason"]}},render:"action"}]},{name:"bug",display:"Bug",description:"Bug管理,支持获取Bug列表,支持获取产品/项目/执行下的Bug、创建Bug、获取Bug详情、修改Bug、删除Bug、激活Bug、关闭Bug、解决Bug",actions:[{name:"list",display:"获取Bug列表,支持获取产品/项目/执行下的Bug",type:"list",method:"get",path:"/{scope}/{scopeID}/bugs",resultType:"list",pagerGetter:"pager",resultGetter:"bugs",pathParams:{scope:{description:"Bug范围",options:[{value:"products",label:"产品"},{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"all",label:"全部"},{value:"unclosed",label:"未关闭"},{value:"assignedtome",label:"指派给我"},{value:"openedbyme",label:"我创建"},{value:"assignedbyme",label:"由我指派"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建Bug",type:"create",method:"post",path:"/bugs",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品",format:"int32"},title:{type:"string",description:"Bug标题"},openedBuild:{type:"array",items:{type:"string"},description:"影响版本,主干是trunk,其他版本使用版本ID"},project:{type:"integer",description:"所属项目",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"},severity:{type:"integer",description:"严重程度,默认是3",format:"int32"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},type:{type:"string",description:"Bug类型(codeerror 代码错误 | config 配置相关 | install 安装部署 | security 安全相关 | performance 性能问题 | standard 标准规范 | automation 测试脚本 | designdefect 设计缺陷 | others 其他)"},steps:{type:"string",description:"重现步骤"},story:{type:"integer",description:"相关需求",format:"int32"}},required:["productID","title","openedBuild"]}}},{name:"get",display:"获取Bug详情",type:"get",method:"get",path:"/bugs/{bugID}",resultType:"object",resultGetter:"bug",pathParams:{bugID:"Bug ID"}},{name:"update",display:"修改Bug",type:"update",method:"put",path:"/bugs/{bugID}",resultType:"object",pathParams:{bugID:"Bug ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"Bug标题"},severity:{type:"integer",description:"严重程度,默认是3",format:"int32"},pri:{type:"integer",description:"优先级,默认是3",format:"int32"},type:{type:"string",description:"Bug类型(codeerror 代码错误 | config 配置相关 | install 安装部署 | security 安全相关 | performance 性能问题 | standard 标准规范 | automation 测试脚本 | designdefect 设计缺陷 | others 其他)"},openedBuild:{type:"array",items:{type:"string"},description:"影响版本,主干是trunk,其他版本使用版本ID"},steps:{type:"string",description:"重现步骤"},project:{type:"integer",description:"所属项目",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"}}}}},{name:"delete",display:"删除Bug",type:"delete",method:"delete",path:"/bugs/{bugID}",resultType:"text",pathParams:{bugID:"Bug ID"},render:"action"},{name:"activate",display:"激活Bug",type:"action",method:"put",path:"/bugs/{bugID}/activate",resultType:"text",pathParams:{bugID:"Bug ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{openedBuild:{type:"array",items:{type:"string"},description:"影响版本, trunk为主干"},assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"close",display:"关闭Bug",type:"action",method:"put",path:"/bugs/{bugID}/close",resultType:"text",pathParams:{bugID:"Bug ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{comment:{type:"string",description:"备注"}}}},render:"action"},{name:"resolve",display:"解决Bug",type:"action",method:"put",path:"/bugs/{bugID}/resolve",resultType:"text",pathParams:{bugID:"Bug ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{resolution:{type:"string",description:"fixed 已解决 | notrepro 无法重现 | bydesign 设计如此 | duplicate 重复Bug | external 外部原因| postponed 延期处理 | willnotfix 不予解决 | tostory 转为需求"},resolvedDate:{type:"string",description:"解决日期,默认今天"},resolvedBuild:{type:"string",description:"解决版本, trunk为主干"},assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}},required:["resolution"]}},render:"action"}]},{name:"testcase",display:"测试用例",description:"测试用例管理,支持获取测试用例列表,支持获取产品/项目/执行下的测试用例、创建测试用例、获取测试用例详情、修改测试用例、删除测试用例",actions:[{name:"list",display:"获取测试用例列表,支持获取产品/项目/执行下的测试用例",type:"list",method:"get",path:"/{scope}/{scopeID}/testcases",resultType:"list",pagerGetter:"pager",resultGetter:"testcases",pathParams:{scope:{description:"测试用例范围",options:[{value:"products",label:"产品"},{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是all",defaultValue:"all",options:[{value:"all",label:"全部"},{value:"wait",label:"未关闭"},{value:"needconfirm",label:"需求变动"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建测试用例",type:"create",method:"post",path:"/testcases",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品",format:"int32"},title:{type:"string",description:"用例标题"},module:{type:"integer",description:"所属模块",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"},pri:{type:"integer",description:"优先级",format:"int32"},type:{type:"string",description:"用例类型(unit 单元测试 | interface 接口测试 | feature 功能测试 | install 安装部署 | config 配置相关 | performance 性能测试 | security 安全相关 | other 其他)"},precondition:{type:"string",description:"前置条件"},steps:{type:"array",items:{type:"string"},description:"用例步骤"},expects:{type:"array",items:{type:"string"},description:"用例步骤期望"},stepType:{type:"array",items:{type:"string"},description:"用例步骤类型(step 步骤 | group 父级步骤)"},project:{type:"integer",description:"所属项目",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"}},required:["productID","title"]}}},{name:"get",display:"获取测试用例详情",type:"get",method:"get",path:"/testcases/{caseID}",resultType:"object",resultGetter:"testcase",pathParams:{caseID:"测试用例ID"}},{name:"update",display:"修改测试用例",type:"update",method:"put",path:"/testcases/{testcasID}",resultType:"object",pathParams:{testcasID:"测试用例ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{title:{type:"string",description:"用例标题"},moudule:{type:"integer",description:"所属模块",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"},pri:{type:"integer",description:"优先级",format:"int32"},type:{type:"string",description:"用例类型(unit 单元测试 | interface 接口测试 | feature 功能测试 | install 安装部署 | config 配置相关 | performance 性能测试 | security 安全相关 | other 其他)"},precondition:{type:"string",description:"前置条件"},steps:{type:"array",items:{type:"string"},description:"用例步骤"},expects:{type:"array",items:{type:"string"},description:"用例步骤期望"},stepType:{type:"array",items:{type:"string"},description:"用例步骤类型(step 步骤 | group 父级步骤)"}},required:["title"]}}},{name:"delete",display:"删除测试用例",type:"delete",method:"delete",path:"/testcases/{testcasID}",resultType:"text",pathParams:{testcasID:"测试用例ID"},render:"action"}]},{name:"task",display:"任务",description:"任务管理,支持获取任务列表,支持获取执行下的任务、创建任务、获取任务详情、修改任务、删除任务、激活任务、关闭任务、完成任务、启动任务",actions:[{name:"list",display:"获取任务列表,支持获取执行下的任务",type:"list",method:"get",path:"/{scope}/{scopeID}/tasks",resultType:"list",pagerGetter:"pager",resultGetter:"tasks",pathParams:{scope:{description:"任务范围",options:[{value:"executions",label:"执行"}]},scopeID:"范围ID"},params:[{name:"status",required:!1,type:"string",description:"状态,默认是unclosed",defaultValue:"unclosed",options:[{value:"all",label:"全部"},{value:"unclosed",label:"未关闭"},{value:"assignedtome",label:"指派给我"},{value:"assignedtome",label:"指派给我"},{value:"myinvolved",label:"由我参与"},{value:"assignedbyme",label:"由我指派"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"name_asc",label:"名称 升序"},{value:"name_desc",label:"名称 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建任务",type:"create",method:"post",path:"/tasks",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"任务名称"},executionID:{type:"integer",description:"所属执行",format:"int32"},type:{type:"string",description:"任务类型"},assignedTo:{type:"string",description:"指派给"},estStarted:{type:"string",description:"预计开始"},deadline:{type:"string",description:"截止日期"},pri:{type:"integer",description:"优先级",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},module:{type:"integer",description:"所属模块",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"},desc:{type:"string",description:"任务描述"}},required:["name","executionID"]}}},{name:"get",display:"获取任务详情",type:"get",method:"get",path:"/tasks/{taskID}",resultType:"object",pathParams:{taskID:"任务ID"}},{name:"update",display:"修改任务",type:"update",method:"put",path:"/tasks/{taskID}",resultType:"object",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"任务名称"},type:{type:"string",description:"任务类型"},assignedTo:{type:"string",description:"指派给"},estStarted:{type:"string",description:"预计开始"},deadline:{type:"string",description:"截止日期"},pri:{type:"integer",description:"优先级",format:"int32"},estimate:{type:"number",description:"预计工时",format:"float"},module:{type:"integer",description:"所属模块",format:"int32"},story:{type:"integer",description:"相关需求",format:"int32"},desc:{type:"string",description:"任务描述"}}}}},{name:"delete",display:"删除任务",type:"delete",method:"delete",path:"/tasks/{taskID}",resultType:"text",pathParams:{taskID:"任务ID"},render:"action"},{name:"activate",display:"激活任务",type:"action",method:"put",path:"/tasks/{taskID}/activate",resultType:"text",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{left:{type:"number",description:"预计剩余",format:"float"},assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"close",display:"关闭任务",type:"action",method:"put",path:"/tasks/{taskID}/close",resultType:"text",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{comment:{type:"string",description:"备注"}}}},render:"action"},{name:"finish",display:"完成任务",type:"action",method:"put",path:"/tasks/{taskID}/finish",resultType:"text",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{currentConsumed:{type:"number",description:"本次消耗",format:"float"},assignedTo:{type:"string",description:"任务名称"},consumed:{type:"number",description:"总计消耗",format:"float"},realStarted:{type:"string",description:"实际开始"},finishedDate:{type:"string",description:"实际完成"},comment:{type:"string",description:"备注"}},required:["currentConsumed","realStarted","finishedDate"]}},render:"action"},{name:"start",display:"启动任务",type:"action",method:"put",path:"/tasks/{taskID}/start",resultType:"text",pathParams:{taskID:"任务ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"任务名称"},realStarted:{type:"string",description:"实际开始"},consumed:{type:"number",description:"总计消耗",format:"float"},left:{type:"number",description:"预计剩余",format:"float"},comment:{type:"string",description:"备注"}},required:["realStarted"]}},render:"action"}]},{name:"feedback",display:"反馈",description:"反馈管理,支持获取反馈列表,支持获取产品下的反馈、创建反馈、获取反馈详情、修改反馈、删除反馈、激活反馈、关闭反馈",actions:[{name:"list",display:"获取反馈列表,支持获取产品下的反馈",type:"list",method:"get",path:"/{scope}/{scopeID}/feedbacks",resultType:"list",pagerGetter:"pager",resultGetter:"feedbacks",pathParams:{scope:{description:"反馈范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是wait",defaultValue:"wait",options:[{value:"all",label:"全部"},{value:"wait",label:"待处理"},{value:"doing",label:"处理中"},{value:"toclosed",label:"待关闭"},{value:"review",label:"待评审"},{value:"assigntome",label:"指派给我"},{value:"openedbyme",label:"由我反馈"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建反馈",type:"create",method:"post",path:"/feedbacks",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{product:{type:"integer",description:"所属产品",format:"int32"},title:{type:"string",description:"标题"},module:{type:"integer",description:"所属模块",format:"int32"},type:{type:"string",description:"类型(story 需求 | task 任务 | bug Bug | todo 待办 | advice 建议 | issue 问题 | risk 风险 | opportunity 机会)"},desc:{type:"string",description:"描述"},feedbackBy:{type:"string",description:"反馈者"},source:{type:"string",description:"来源"}},required:["product","title"]}}},{name:"get",display:"获取反馈详情",type:"get",method:"get",path:"/feedbacks/{feedbackID}",resultType:"object",resultGetter:"feedback",pathParams:{feedbackID:"反馈ID"}},{name:"update",display:"修改反馈",type:"update",method:"put",path:"/feedbacks/{feedbackID}",resultType:"object",pathParams:{feedbackID:"反馈ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{product:{type:"integer",description:"所属产品",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},title:{type:"string",description:"标题"},type:{type:"string",description:"类型(story 需求 | task 任务 | bug Bug | todo 待办 | advice 建议 | issue 问题 | risk 风险 | opportunity 机会)"},desc:{type:"string",description:"描述"},feedbackBy:{type:"string",description:"反馈者"},source:{type:"string",description:"来源"}},required:["product","title"]}}},{name:"delete",display:"删除反馈",type:"delete",method:"delete",path:"/feedbacks/{feedbackID}",resultType:"text",pathParams:{feedbackID:"反馈ID"},render:"action"},{name:"activate",display:"激活反馈",type:"action",method:"put",path:"/feedbacks/{feedbackID}/activate",resultType:"text",pathParams:{feedbackID:"反馈ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"close",display:"关闭反馈",type:"action",method:"put",path:"/feedbacks/{feedbackID}/close",resultType:"text",pathParams:{feedbackID:"反馈ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(commented 已处理 | repeat 重复 | refuse 不予采纳)"},comment:{type:"string",description:"备注"}},required:["closedReason"]}},render:"action"}]},{name:"ticket",display:"工单",description:"工单管理,支持获取工单列表,支持获取产品下的工单、创建工单、获取工单详情、修改工单、删除工单、激活工单、关闭工单",actions:[{name:"list",display:"获取工单列表,支持获取产品下的工单",type:"list",method:"get",path:"/{scope}/{scopeID}/tickets",resultType:"list",pagerGetter:"pager",resultGetter:"tickets",pathParams:{scope:{description:"工单范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"},params:[{name:"browseType",required:!1,type:"string",description:"状态,默认是wait",defaultValue:"wait",options:[{value:"all",label:"全部"},{value:"unclosed",label:"未关闭"},{value:"wait",label:"待处理"},{value:"doing",label:"处理中"},{value:"done",label:"待关闭"},{value:"finishedbyme",label:"由我解决"},{value:"assigntome",label:"指派给我"},{value:"openedbyme",label:"由我创建"}]},{name:"orderBy",required:!1,type:"string",description:"排序",options:[{value:"id_asc",label:"ID 升序"},{value:"id_desc",label:"ID 降序"},{value:"title_asc",label:"标题 升序"},{value:"title_desc",label:"标题 降序"},{value:"status_asc",label:"状态 升序"},{value:"status_desc",label:"状态 降序"}]},{name:"recPerPage",required:!1,type:"number",description:"每页数量,不超过1000"},{name:"pageID",required:!1,type:"number",description:"页码,从第1页开始"}]},{name:"create",display:"创建工单",type:"create",method:"post",path:"/tickets",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{product:{type:"integer",description:"所属产品",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},title:{type:"string",description:"标题"},type:{type:"string",description:"类型(code 程序报错 | data 数据错误 | stuck 流程卡断 | security 安全问题 | affair 事务)"},desc:{type:"string",description:"描述"},assignedTo:{type:"string",description:"指派给"},deadline:{type:"string",description:"截止日期"},openedBuild:{type:"array",items:{type:"string"},description:"影响版本"}},required:["product","title"]}}},{name:"get",display:"获取工单详情",type:"get",method:"get",path:"/tickets/{ticketID}",resultType:"object",resultGetter:"ticket",pathParams:{ticketID:"工单ID"}},{name:"update",display:"修改工单",type:"update",method:"put",path:"/tickets/{ticketID}",resultType:"object",pathParams:{ticketID:"工单ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{product:{type:"integer",description:"所属产品",format:"int32"},module:{type:"integer",description:"所属模块",format:"int32"},title:{type:"string",description:"标题"},type:{type:"string",description:"类型(code 程序报错 | data 数据错误 | stuck 流程卡断 | security 安全问题 | affair 事务)"},desc:{type:"string",description:"描述"},assignedTo:{type:"string",description:"指派给"},deadline:{type:"string",description:"截止日期"},openedBuild:{type:"array",items:{type:"string"},description:"影响版本"}}}}},{name:"delete",display:"删除工单",type:"delete",method:"delete",path:"/tickets/{ticketID}",resultType:"text",pathParams:{ticketID:"工单ID"},render:"action"},{name:"activate",display:"激活工单",type:"action",method:"put",path:"/tickets/{ticketID}/activate",resultType:"text",pathParams:{ticketID:"工单ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{assignedTo:{type:"string",description:"指派给"},comment:{type:"string",description:"备注"}}}},render:"action"},{name:"close",display:"关闭工单",type:"action",method:"put",path:"/tickets/{ticketID}/close",resultType:"text",pathParams:{ticketID:"工单ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{closedReason:{type:"string",description:"关闭原因(commented 已处理 | repeat 重复 | refuse 不予处理)"},comment:{type:"string",description:"备注"}},required:["closedReason","comment"]}},render:"action"}]},{name:"system",display:"应用",description:"应用管理,支持获取应用列表,支持获取产品下的应用、创建应用、修改应用",actions:[{name:"list",display:"获取应用列表,支持获取产品下的应用",type:"list",method:"get",path:"/{scope}/{scopeID}/systems",resultType:"list",pagerGetter:"pager",pathParams:{scope:{description:"应用范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"}},{name:"create",display:"创建应用",type:"create",method:"post",path:"/systems",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品",format:"int32"},integrated:{type:"integer",description:"是否集成应用(0 否| 1 是)",format:"int32"},children:{type:"array",items:{type:"string"},description:"集成应用需要包含其他应用,非集成应用传空数组[]"},name:{type:"string",description:"应用名称"},desc:{type:"string",description:"描述"}},required:["productID","integrated","children","name"]}}},{name:"update",display:"修改应用",type:"update",method:"put",path:"/systems/{systemID}",resultType:"object",pathParams:{systemID:"应用ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"应用名称"},children:{type:"array",items:{type:"string"},description:"集成应用需要包含其他应用,非集成应用传空数组[]"},desc:{type:"string",description:"描述"}},required:["name","children"]}}}]},{name:"build",display:"版本",description:"版本管理,支持获取版本列表,支持获取项目/执行下的版本、创建版本/构建、修改版本、删除版本",actions:[{name:"list",display:"获取版本列表,支持获取项目/执行下的版本",type:"list",method:"get",path:"/{scope}/{scopeID}/builds",resultType:"list",pagerGetter:"pager",resultGetter:"builds",pathParams:{scope:{description:"版本范围",options:[{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"}},{name:"create",display:"创建版本/构建",type:"create",method:"post",path:"/builds",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{executionID:{type:"integer",description:"所属执行/迭代",format:"int32"},product:{type:"integer",description:"所属产品",format:"int32"},name:{type:"string",description:"构建名称"},system:{type:"integer",description:"所属应用",format:"int32"},builder:{type:"string",description:"构建者"},date:{type:"string",description:"打包日期"},scmPath:{type:"string",description:"源代码地址"},filePath:{type:"string",description:"下载地址"},desc:{type:"string",description:"描述"}},required:["executionID","product","name","system","builder","date"]}}},{name:"update",display:"修改版本",type:"update",method:"put",path:"/builds/{buildID}",resultType:"object",pathParams:{buildID:"版本ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{execution:{type:"integer",description:"所属执行/迭代",format:"int32"},product:{type:"integer",description:"所属产品",format:"int32"},name:{type:"string",description:"构建名称"},system:{type:"integer",description:"所属应用",format:"int32"},builder:{type:"string",description:"构建者"},date:{type:"string",description:"打包日期"},scmPath:{type:"string",description:"源代码地址"},filePath:{type:"string",description:"下载地址"},desc:{type:"string",description:"描述"}},required:["execution","product","name","system","builder","date"]}}},{name:"delete",display:"删除版本",type:"delete",method:"delete",path:"/builds/{buildID}",resultType:"text",pathParams:{buildID:"版本ID"},render:"action"}]},{name:"testtask",display:"测试单",description:"测试单管理,支持获取测试单列表,支持获取产品/项目/执行下的测试单、创建测试单、修改测试单、删除测试单",actions:[{name:"list",display:"获取测试单列表,支持获取产品/项目/执行下的测试单",type:"list",method:"get",path:"/{scope}/{scopeID}/testtasks",resultType:"list",pagerGetter:"pager",resultGetter:"testtasks",pathParams:{scope:{description:"测试单范围",options:[{value:"products",label:"产品"},{value:"projects",label:"项目"},{value:"executions",label:"执行"}]},scopeID:"范围ID"}},{name:"create",display:"创建测试单",type:"create",method:"post",path:"/testtasks",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品ID",format:"int32"},name:{type:"string",description:"测试单名称"},build:{type:"integer",description:"提测构建/版本",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"},type:{type:"array",items:{type:"string"},description:"类型(integrate 集成测试 | system 系统测试 | acceptance 验收测试 | performance 性能测试 | safety 安全测试)"},owner:{type:"string",description:"负责人"},status:{type:"string",description:"状态(wait 未开始 | doing 进行中 | done 已关闭 | blocked 被阻塞)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},desc:{type:"string",description:"描述"}},required:["productID","name","build","begin","end"]}}},{name:"update",display:"修改测试单",type:"update",method:"put",path:"/testtasks/{testtaskID}",resultType:"object",pathParams:{testtaskID:"测试单ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{name:{type:"string",description:"测试单名称"},build:{type:"integer",description:"提测构建/版本",format:"int32"},execution:{type:"integer",description:"所属执行",format:"int32"},type:{type:"array",items:{type:"string"},description:"类型(integrate 集成测试 | system 系统测试 | acceptance 验收测试 | performance 性能测试 | safety 安全测试)"},owner:{type:"string",description:"负责人"},status:{type:"string",description:"状态(wait 未开始 | doing 进行中 | done 已关闭 | blocked 被阻塞)"},begin:{type:"string",description:"开始日期"},end:{type:"string",description:"结束日期"},desc:{type:"string",description:"描述"}},required:["name","build","begin","end"]}}},{name:"delete",display:"删除测试单",type:"delete",method:"delete",path:"/testtasks/{testtaskID}",resultType:"text",pathParams:{testtaskID:"测试单ID"},render:"action"}]},{name:"release",display:"发布",description:"发布管理,支持获取发布列表,支持获取产品下的发布、创建发布、修改发布、删除发布",actions:[{name:"list",display:"获取发布列表,支持获取产品下的发布",type:"list",method:"get",path:"/{scope}/{scopeID}/releases",resultType:"list",pagerGetter:"pager",resultGetter:"releases",pathParams:{scope:{description:"发布范围",options:[{value:"products",label:"产品"}]},scopeID:"范围ID"}},{name:"create",display:"创建发布",type:"create",method:"post",path:"/releases",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{productID:{type:"integer",description:"所属产品",format:"int32"},system:{type:"integer",description:"所属应用",format:"int32"},name:{type:"string",description:"应用版本号"},build:{type:"array",items:{type:"string"},description:"包含构建"},status:{type:"string",description:"状态(wait 未开始 | normal 已发布 | fail 发布失败 | terminate 停止维护)"},date:{type:"string",description:"计划发布日期"},desc:{type:"string",description:"描述"}},required:["productID","system","name","build","date"]}}},{name:"update",display:"修改发布",type:"update",method:"put",path:"/releases/{releasID}",resultType:"object",pathParams:{releasID:"发布ID"},requestBody:{required:!0,type:"object",schema:{type:"object",properties:{system:{type:"integer",description:"所属应用",format:"int32"},name:{type:"string",description:"应用版本号"},build:{type:"array",items:{type:"string"},description:"包含构建"},status:{type:"string",description:"状态(wait 未开始 | normal 已发布 | fail 发布失败 | terminate 停止维护)"},date:{type:"string",description:"计划发布日期"},desc:{type:"string",description:"描述"}},required:["system","name","build","date"]}}},{name:"delete",display:"删除发布",type:"delete",method:"delete",path:"/releases/{releasID}",resultType:"text",pathParams:{releasID:"发布ID"},render:"action"}]},{name:"file",display:"附件",description:"附件管理,支持编辑附件,修改附件的名称、删除附件",actions:[{name:"create",display:"编辑附件,修改附件的名称",type:"create",method:"post",path:"/files",resultType:"object",requestBody:{required:!0,type:"object",schema:{type:"object",properties:{fileName:{type:"string",description:"附件名称"}},required:["fileName"]}}},{name:"delete",display:"删除附件",type:"delete",method:"delete",path:"/files/{fileID}",resultType:"text",pathParams:{fileID:"附件ID"},render:"action"}]}];var V=qX(Z(PQ)),JQ=NQ(V);function Z(Q){if(Array.isArray(Q))return Q.map((X)=>Z(X));if(Q&&typeof Q==="object"&&!(Q instanceof Function)){let X={};for(let[$,J]of Object.entries(Q))X[$]=Z(J);return X}return Q}function WQ(Q){if(Q===null||typeof Q!=="object")return Q;if(Object.isFrozen(Q))return Q;for(let X of Object.keys(Q))WQ(Q[X]);return Object.freeze(Q)}function DQ(Q){return WQ(Q)}function c(Q){return Q.actions.forEach(DQ),WQ(Q)}function qX(Q){return Q.forEach(c),Q}function EQ(Q,X){let $=X.toLowerCase();return Q.findIndex((J)=>String(J.name).toLowerCase()===$)}function AX(Q,X){let $=Q.slice();for(let J of X){let W=EQ($,String(J.name)),D=DQ(Z(J));if(W>=0)$[W]=D;else $.push(D)}return $}function GX(Q,X){return c({...Q,...Z(X),actions:AX(Q.actions,X.actions)})}function NQ(Q){return new Map(Q.map((X)=>[X.name.toLowerCase(),X]))}function kQ(){JQ=NQ(V)}function CX(Q){if(!Q||typeof Q.name!=="string"||!Array.isArray(Q.actions))throw new B("E_INVALID_MODULE_DEFINITION")}function MX(Q){if(!Q||typeof Q.name!=="string"||typeof Q.path!=="string"||typeof Q.method!=="string")throw new B("E_INVALID_ACTION_DEFINITION")}function YQ(Q,X={}){for(let $ of I(Q)){CX($);let J=$.name.toLowerCase(),W=V.findIndex((D)=>D.name.toLowerCase()===J);if(W>=0)V[W]=X.replace?c(Z($)):GX(V[W],$);else V.push(c(Z($)))}kQ()}function HQ(Q,X){let $=Q.toLowerCase(),J=JQ.get($);if(!J)throw new B("E_INVALID_MODULE",{module:Q});let W=J.actions.slice();for(let q of I(X)){MX(q);let A=EQ(W,String(q.name)),M=DQ(Z(q));if(A>=0)W[A]=M;else W.push(M)}let D=c({...J,actions:W}),H=V.findIndex((q)=>q.name.toLowerCase()===$);V[H]=D,kQ()}function S(Q){let X=JQ.get(Q.toLowerCase());if(!X)throw new B("E_INVALID_MODULE",{module:Q});return X}function m(Q,X){let $=S(Q),J=X==="ls"?"list":X,W=$.actions.find((H)=>String(H.name).toLowerCase()===J.toLowerCase());if(W)return W;if(!new Set(["list","get","create","update","delete"]).has(J)){let H=$.actions.find((q)=>q.type==="action"&&String(q.name).toLowerCase()===J.toLowerCase());if(H)return H}throw new B("E_INVALID_ACTION",{module:Q,action:X})}function BQ(){return V.map((Q)=>Q.name)}var RX={product:"products",project:"projects",execution:"executions"},UX=["execution","project","product"];function KX(Q){for(let X of UX){let $=Q[X]??Q[`${X}ID`];if($===void 0||$===null||$==="")continue;let J=Number($);if(!Number.isNaN(J))return{scope:RX[X],scopeID:J}}return}function LX(Q,X){return Q.path.replace(/\{(\w+)\}/g,($,J)=>{let W=X[J];if(W===void 0||W==="")throw new B("E_MISSING_PARAM",{param:J});return String(W)})}function TX(Q){if(Q===void 0)return;if(typeof Q==="string")try{let X=JSON.parse(Q);return X&&typeof X==="object"&&!Array.isArray(X)?X:void 0}catch{return}return Q&&typeof Q==="object"&&!Array.isArray(Q)?Q:void 0}var OX=new Set(["true","1","yes","on"]),VX=new Set(["false","0","no","off"]);function jX(Q,X,$){if(Q===void 0||Q===null)return Q;if(X==="number"||X==="integer"){let J=Number(Q);return Number.isNaN(J)?Q:J}if(X==="boolean"){if(typeof Q==="boolean")return Q;if(typeof Q==="number"){if(Q===1)return!0;if(Q===0)return!1;throw new B("E_INVALID_PARAM",{param:$,value:String(Q)})}if(typeof Q==="string"){let J=Q.trim().toLowerCase();if(OX.has(J))return!0;if(VX.has(J))return!1;throw new B("E_INVALID_PARAM",{param:$,value:Q})}throw new B("E_INVALID_PARAM",{param:$,value:String(Q)})}return Q}function gQ(Q,X,$={}){let J=m(Q.name,X),W={},D=Object.keys(J.pathParams??{});if(D.includes("scope")){let Y=KX($);if(!Y)throw new B("E_MISSING_PARAM",{param:"product/project/execution"});W.scope=Y.scope,W.scopeID=Y.scopeID}let H=D.find((Y)=>Y.endsWith("ID")&&Y!=="scopeID"),q=$.id??$[`${Q.name}ID`]??(H?$[H]:void 0),A=q===void 0?void 0:Number(q);if(H&&A!==void 0&&!Number.isNaN(A))W[H]=A;for(let Y of D){if(Y==="scope"||Y==="scopeID"||W[Y]!==void 0)continue;let G=J.pathParams?.[Y],C=$[Y];if(C!==void 0){W[Y]=C;continue}if(typeof G==="object"){if(G.defaultValue!==void 0)W[Y]=G.defaultValue;else if(G.options?.[0]?.value!==void 0)W[Y]=G.options[0].value}if(W[Y]===void 0)throw new B("E_MISSING_PARAM",{param:Y})}let M={};for(let Y of J.params??[]){let G=$[Y.name];if(G===void 0&&Y.name==="pageID")G=$.page;if(G===void 0)G=Y.defaultValue??Y.options?.[0]?.value;if(G===void 0&&Y.required)throw new B("E_MISSING_PARAM",{param:Y.name});if(G!==void 0)M[Y.name]=G}let R=TX($.data);if(J.requestBody?.schema?.type==="object"){R=R?{...R}:{};let Y=J.requestBody.schema,G=new Set(Y.required??[]);for(let[C,K]of Object.entries(Y.properties??{})){let MQ=Object.prototype.hasOwnProperty.call(R,C),yQ=Object.prototype.hasOwnProperty.call($,C),U=MQ?R[C]:yQ?$[C]:K.defaultValue;if(U===void 0&&(K.required||G.has(C)))throw new B("E_MISSING_PARAM",{param:C});if(U=jX(U,K.type,C),K.type==="array"&&U!==void 0&&U!==null&&!Array.isArray(U)){if(typeof U==="string")U=U.split(",");else if(!MQ||!L(U))U=[U]}if(U!==void 0)R[C]=U}}return{module:Q.name,action:J,params:$,path:LX(J,W),query:M,data:R,id:A===void 0||Number.isNaN(A)?void 0:A}}function hQ(Q,X){let $=Q.resultGetter;if(!$)return X.data??X;if(typeof $==="function")return $(X,{});if(typeof $==="string")return T(X,$);let J={};for(let[W,D]of Object.entries($))J[W]=X[D];return J}function bQ(Q,X){let $=Q.pagerGetter;if(!$)return X.pager;if(typeof $==="function")return $(X,{});if(typeof $==="string")return T(X,$);let J=X[$.pageID],W=X[$.recPerPage],D=X[$.recTotal];if(J===void 0||W===void 0||D===void 0)return;return{pageID:Number(J),recPerPage:Number(W),recTotal:Number(D)}}function IX(Q){let[X,$]=Q.split("/");if(!$?.length)return{moduleName:X,actionName:"list"};if(Number.isInteger(Number($)))return{moduleName:X,actionName:"get",id:Number($)};return{moduleName:X,actionName:$}}function ZX(Q){return Boolean(Q.filter&&Q.filter.length>0||Q.search&&Q.search.length>0||Q.sort||Q.limit||Q.pick&&Q.pick.length>0)}function FX(Q,X){if(Array.isArray(Q)){if(!ZX(X))return Q;if(Q.every(L))return F(Q,{filter:X.filter,search:X.search,searchFields:X.searchFields,sort:X.sort,limit:X.limit,pick:X.pick});let $=Number(X.limit);return Number.isFinite($)&&$>=0?Q.slice(0,Math.floor($)):Q}if(L(Q)&&X.pick&&X.pick.length>0)return F(Q,{pick:X.pick});return Q}function _X(Q,X,$){if(!X||typeof X!=="object"||Array.isArray(X))return{status:"success",data:X};let J=X,W=J.status==="fail"?"fail":"success",D=FX(hQ(Q.action,J),$),H=bQ(Q.action,J);return{status:W,message:typeof J.message==="string"?J.message:void 0,data:D,pager:H?{total:Number(H.recTotal),page:Number(H.pageID),recPerPage:Number(H.recPerPage)}:void 0}}async function qQ(Q,X={},$={}){let J=j(),W=$.client??J.client;if(!W)throw new B("E_NO_GLOBAL_CLIENT");let{moduleName:D,actionName:H,id:q}=IX(Q),A=S(D),M=X.recPerPage??$.recPerPage??J.recPerPage,R={...q!==void 0?{id:q}:{},...X,...M!==void 0?{recPerPage:M}:{}},Y=gQ(A,H,R),G=await W.request(Y.path,{method:String(Y.action.method).toUpperCase(),query:Y.query,body:Y.data,timeout:$.timeout??J.timeout,insecure:$.insecure??J.insecure}),C={...$,limit:$.limit??J.limit},K=_X(Y,G,C);if(K.status==="fail"&&($.throwOnFail??J.throwOnFail))throw new B("E_API_FAILED",{message:K.message??""},K);return K}var AQ="2026-06-27T10:57:52.736Z",GQ="0.3.0";var CQ=globalThis;CQ.ZentaoAPI=i;if(CQ.window)CQ.window.ZentaoAPI=i;})();
package/dist/index.d.ts CHANGED
@@ -2,7 +2,8 @@ export { ZentaoClient } from './client/index.js';
2
2
  export { ERRORS, ZentaoError, type ErrorCode } from './misc/errors.js';
3
3
  export { getGlobalOptions, setGlobalOptions } from './misc/global-options.js';
4
4
  export { ZENTAO_PROFILES_STORAGE_KEY, addProfile, deleteProfile, getAllProfiles, getProfile, getProfileKey, switchProfile, } from './profiles/index.js';
5
- export { defineModuleActions, defineModules, type DefineModulesOptions, getModule, getModuleAction, } from './modules/registry.js';
5
+ export { defineModuleActions, defineModules, type DefineModulesOptions, getModuleNames, getModule, getModuleAction, } from './modules/registry.js';
6
6
  export { request } from './request/index.js';
7
+ export { pickFields, pickFieldsSingle, filterData, searchData, sortData, processData, } from './utils/index.js';
7
8
  export { BUILD, VERSION } from './version.js';
8
- export type { ApiListResponse, ApiResponse, ClientRequestOptions, GlobalOptions, HttpMethod, ListPagerInfo, LoginResponse, ModuleAction, ModuleActionMethod, ModuleActionName, ModuleActionPagerGetterMap, ModuleActionParam, ModuleActionParamOption, ModuleActionRequestBody, ModuleActionResponse, ModuleActionResultRender, ModuleActionResultRenderType, ModuleActionResultType, ModuleActionType, ModuleDefinition, ModuleName, Pager, RequestOptions, ResolvedModuleCommand, ResponseData, ServerConfig, ZentaoProfile, ZentaoProfileConfig, ZentaoProfileRecord, ZentaoProfilesStore, ZentaoClientOptions, } from './types/index.js';
9
+ export type { ApiListResponse, ApiResponse, ClientRequestOptions, DataRecord, DataRecordFilter, DataRecordFilterGroup, GlobalOptions, HttpMethod, ListPagerInfo, LoginResponse, ModuleAction, ModuleActionMethod, ModuleActionName, ModuleActionPagerGetterMap, ModuleActionParam, ModuleActionParamOption, ModuleActionRequestBody, ModuleActionResponse, ModuleActionResultRender, ModuleActionResultRenderType, ModuleActionResultType, ModuleActionType, ModuleDefinition, ModuleName, Pager, ProcessListOptions, ProcessSingleOptions, RequestOptions, ResolvedModuleCommand, ResponseData, ServerConfig, SortExpr, SortFn, ZentaoProfile, ZentaoProfileConfig, ZentaoProfileRecord, ZentaoProfilesStore, ZentaoClientOptions, } from './types/index.js';
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export { ZentaoClient } from './client/index.js';
2
2
  export { ERRORS, ZentaoError } from './misc/errors.js';
3
3
  export { getGlobalOptions, setGlobalOptions } from './misc/global-options.js';
4
4
  export { ZENTAO_PROFILES_STORAGE_KEY, addProfile, deleteProfile, getAllProfiles, getProfile, getProfileKey, switchProfile, } from './profiles/index.js';
5
- export { defineModuleActions, defineModules, getModule, getModuleAction, } from './modules/registry.js';
5
+ export { defineModuleActions, defineModules, getModuleNames, getModule, getModuleAction, } from './modules/registry.js';
6
6
  export { request } from './request/index.js';
7
+ export { pickFields, pickFieldsSingle, filterData, searchData, sortData, processData, } from './utils/index.js';
7
8
  export { BUILD, VERSION } from './version.js';
@@ -2,29 +2,77 @@ import { ZentaoError } from '../misc/errors.js';
2
2
  import { getGlobalOptions } from '../misc/global-options.js';
3
3
  import { getModule } from '../modules/registry.js';
4
4
  import { extractPager, extractResult, resolveModuleCommand } from '../modules/resolve.js';
5
+ import { isRecord, processData } from '../utils/index.js';
5
6
  /** 将 `moduleName/methodName` 形式的请求名拆成模块名和动作名。 */
6
7
  function splitRequestName(name) {
7
- const index = name.indexOf('/');
8
- if (index <= 0 || index === name.length - 1) {
9
- throw new ZentaoError('E_INVALID_REQUEST_NAME');
8
+ const [moduleName, actionName] = name.split('/');
9
+ // 如果没有指定 actionName
10
+ if (!actionName?.length) {
11
+ return {
12
+ moduleName,
13
+ actionName: 'list',
14
+ };
15
+ }
16
+ // 如果 actionName 为数值
17
+ if (Number.isInteger(Number(actionName))) {
18
+ return {
19
+ moduleName,
20
+ actionName: 'get',
21
+ id: Number(actionName),
22
+ };
10
23
  }
11
24
  return {
12
- moduleName: name.slice(0, index),
13
- actionName: name.slice(index + 1),
25
+ moduleName,
26
+ actionName,
14
27
  };
15
28
  }
29
+ /** 判断本次调用是否携带了需要本地处理列表的选项。 */
30
+ function hasListProcessing(options) {
31
+ return Boolean((options.filter && options.filter.length > 0) ||
32
+ (options.search && options.search.length > 0) ||
33
+ options.sort ||
34
+ options.limit ||
35
+ (options.pick && options.pick.length > 0));
36
+ }
37
+ /**
38
+ * 对归一化后的业务数据应用本地处理(过滤 → 搜索 → 排序 → 限制数量 → 摘取)。
39
+ *
40
+ * - 对象列表:交由 {@link processData} 完整处理。
41
+ * - 基本类型数组:仅 `limit` 生效(按数量截断),避免破坏原始元素。
42
+ * - 单条对象:只有 `pick` 生效。
43
+ * - 其他形态原样返回。
44
+ */
45
+ function applyProcessing(data, options) {
46
+ if (Array.isArray(data)) {
47
+ if (!hasListProcessing(options))
48
+ return data;
49
+ if (data.every(isRecord)) {
50
+ return processData(data, {
51
+ filter: options.filter,
52
+ search: options.search,
53
+ searchFields: options.searchFields,
54
+ sort: options.sort,
55
+ limit: options.limit,
56
+ pick: options.pick,
57
+ });
58
+ }
59
+ // 非对象数组(如 ID 列表)只能按数量截断,其余处理不适用。
60
+ const limit = Number(options.limit);
61
+ return Number.isFinite(limit) && limit >= 0 ? data.slice(0, Math.floor(limit)) : data;
62
+ }
63
+ if (isRecord(data) && options.pick && options.pick.length > 0) {
64
+ return processData(data, { pick: options.pick });
65
+ }
66
+ return data;
67
+ }
16
68
  /** 将禅道原始响应归一化为稳定的 ResponseData 结构。 */
17
- function normalizeResponse(command, raw, limit) {
69
+ function normalizeResponse(command, raw, options) {
18
70
  if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
19
71
  return { status: 'success', data: raw };
20
72
  }
21
73
  const record = raw;
22
74
  const status = record.status === 'fail' ? 'fail' : 'success';
23
- let data = extractResult(command.action, record);
24
- const numericLimit = limit === undefined ? undefined : Number(limit);
25
- if (Array.isArray(data) && numericLimit !== undefined && !Number.isNaN(numericLimit)) {
26
- data = data.slice(0, numericLimit);
27
- }
75
+ const data = applyProcessing(extractResult(command.action, record), options);
28
76
  const pager = extractPager(command.action, record);
29
77
  return {
30
78
  status,
@@ -57,11 +105,15 @@ export async function request(name, params = {}, options = {}) {
57
105
  if (!client) {
58
106
  throw new ZentaoError('E_NO_GLOBAL_CLIENT');
59
107
  }
60
- const { moduleName, actionName } = splitRequestName(name);
108
+ const { moduleName, actionName, id } = splitRequestName(name);
61
109
  const module = getModule(moduleName);
62
110
  // recPerPage 是最常用的列表参数,允许在全局或本次调用中统一覆盖。
63
111
  const recPerPage = params.recPerPage ?? options.recPerPage ?? globals.recPerPage;
64
- const mergedParams = recPerPage === undefined ? params : { ...params, recPerPage };
112
+ const mergedParams = {
113
+ ...(id !== undefined ? { id } : {}),
114
+ ...params,
115
+ ...(recPerPage !== undefined ? { recPerPage } : {}),
116
+ };
65
117
  const command = resolveModuleCommand(module, actionName, mergedParams);
66
118
  const raw = await client.request(command.path, {
67
119
  method: String(command.action.method).toUpperCase(),
@@ -70,7 +122,9 @@ export async function request(name, params = {}, options = {}) {
70
122
  timeout: options.timeout ?? globals.timeout,
71
123
  insecure: options.insecure ?? globals.insecure,
72
124
  });
73
- const response = normalizeResponse(command, raw, options.limit ?? globals.limit);
125
+ // limit 现归入本地处理选项;本次调用优先,缺省回落到全局默认。
126
+ const processOptions = { ...options, limit: options.limit ?? globals.limit };
127
+ const response = normalizeResponse(command, raw, processOptions);
74
128
  if (response.status === 'fail' && (options.throwOnFail ?? globals.throwOnFail)) {
75
129
  throw new ZentaoError('E_API_FAILED', { message: response.message ?? '' }, response);
76
130
  }
@@ -43,13 +43,11 @@ export interface ClientRequestOptions {
43
43
  insecure?: boolean;
44
44
  }
45
45
  /** 高阶 `request("moduleName/methodName")` 的单次调用选项。 */
46
- export interface RequestOptions {
46
+ export interface RequestOptions extends ProcessListOptions {
47
47
  /** 本次调用使用的客户端;优先级高于全局客户端。 */
48
48
  client?: ZentaoClient;
49
49
  /** 本次调用使用的每页记录数,优先级高于全局 `recPerPage`。 */
50
50
  recPerPage?: string;
51
- /** 本次调用限制返回列表数量,优先级高于全局 `limit`。 */
52
- limit?: string;
53
51
  /** 本次调用超时时间。 */
54
52
  timeout?: number;
55
53
  /** 本次调用 TLS 跳过证书验证选项;仅 Node.js 运行时支持。 */
@@ -282,6 +280,48 @@ export interface ModuleDefinition {
282
280
  /** 模块支持的动作集合。 */
283
281
  actions: ModuleAction[];
284
282
  }
283
+ /** 本地数据处理的基础记录类型,对应一条对象数据。 */
284
+ export type DataRecord = Record<string, unknown>;
285
+ /** 单条过滤条件,字段名支持 `.` 访问子字段。 */
286
+ export interface DataRecordFilter {
287
+ /** 字段路径,例如 `status` 或 `assignedTo.id`。 */
288
+ key: string;
289
+ /** 比较运算符。 */
290
+ operator: '=' | '!=' | '>' | '<' | '>=' | '<=' | '~' | '!~';
291
+ /** 比较值;数组用于 `=`/`!=`/`~`/`!~` 的“任一/全不”匹配。 */
292
+ value: string | number | boolean | string[];
293
+ }
294
+ /** 一组过滤条件,组内按 `operator` 组合;多组之间按 AND 组合。 */
295
+ export interface DataRecordFilterGroup {
296
+ /** 组内条件的组合方式。 */
297
+ operator: 'AND' | 'OR';
298
+ /** 组内条件列表。 */
299
+ conditions: DataRecordFilter[];
300
+ }
301
+ /** 排序表达式,格式为 `字段:asc|desc`。 */
302
+ export type SortExpr = `${string}:${'asc' | 'desc'}`;
303
+ /** 自定义排序比较函数。 */
304
+ export type SortFn = (a: DataRecord, b: DataRecord) => number;
305
+ /** {@link processData} 处理列表时的选项;执行顺序为 过滤 → 搜索 → 排序 → 限制数量 → 摘取。 */
306
+ export interface ProcessListOptions {
307
+ /** 过滤表达式列表,例如 `["status=active", "pri>=2"]`,多条之间按 AND 组合。 */
308
+ filter?: string[];
309
+ /** 模糊搜索关键词组,组内空格分隔为 OR,多组之间按 AND 组合。 */
310
+ search?: string[];
311
+ /** 限定搜索字段,缺省时搜索全部字段。 */
312
+ searchFields?: string[];
313
+ /** 排序表达式,多个字段以英文逗号分隔,例如 `pri:desc,id:asc`。 */
314
+ sort?: string;
315
+ /** 限制返回列表数量,在排序后、摘取前截断;不改变服务端页大小。 */
316
+ limit?: string;
317
+ /** 摘取字段路径列表。 */
318
+ pick?: string[];
319
+ }
320
+ /** {@link processData} 处理单条对象时的选项。 */
321
+ export interface ProcessSingleOptions {
322
+ /** 摘取字段路径列表。 */
323
+ pick?: string[];
324
+ }
285
325
  /** 将模块动作和参数解析后的可执行请求描述。 */
286
326
  export interface ResolvedModuleCommand {
287
327
  /** 模块名称。 */
@@ -0,0 +1 @@
1
+ export declare function asArray<T>(value: T | T[]): T[];
@@ -0,0 +1,3 @@
1
+ export function asArray(value) {
2
+ return Array.isArray(value) ? value : [value];
3
+ }
@@ -0,0 +1,24 @@
1
+ import type { DataRecord, DataRecordFilterGroup, ProcessListOptions, ProcessSingleOptions, SortExpr, SortFn } from '../types/index.js';
2
+ /** 从单条对象中摘取指定字段,支持通过 `.` 访问子字段,保留嵌套结构。 */
3
+ export declare function pickFieldsSingle(data: DataRecord, fields: string[]): DataRecord;
4
+ /** 对列表中的每条对象摘取指定字段。 */
5
+ export declare function pickFields(data: DataRecord[], fields: string[]): DataRecord[];
6
+ /** 按条件组过滤列表,多组之间按 AND 组合。 */
7
+ export declare function filterData(data: DataRecord[], filterGroups: DataRecordFilterGroup[]): DataRecord[];
8
+ /**
9
+ * 对列表做大小写不敏感的模糊匹配。
10
+ *
11
+ * 每个 `keywordGroups` 元素是一个关键词串,组内以空白分隔为 OR;多组之间按 AND 组合。
12
+ */
13
+ export declare function searchData(data: DataRecord[], keywordGroups: string[], searchFields?: string[]): DataRecord[];
14
+ /**
15
+ * 对列表排序,返回新数组(不修改入参)。
16
+ *
17
+ * `sortFields` 的每个元素可以是 `字段:asc|desc` 表达式或自定义比较函数,按先后顺序生效;
18
+ * 数值字段按数字比较,否则按字符串 `localeCompare`。
19
+ */
20
+ export declare function sortData(data: DataRecord[], sortFields: (SortExpr | SortFn)[]): DataRecord[];
21
+ /** 处理单条对象:仅支持字段摘取。 */
22
+ export declare function processData(data: DataRecord, options: ProcessSingleOptions): DataRecord;
23
+ /** 处理列表:按 过滤 → 搜索 → 排序 → 限制数量 → 摘取 的顺序执行。 */
24
+ export declare function processData(data: DataRecord[], options: ProcessListOptions): DataRecord[];
Binary file
@@ -1,6 +1,4 @@
1
- /** 判断值是否为普通对象(非数组、非 null)。 */
2
- export declare function isRecord(value: unknown): value is Record<string, unknown>;
3
- /** 将用户传入的站点根地址规范化,兼容误传入 `/api.php/v2` 的场景。 */
4
- export declare function normalizeSiteUrl(baseUrl: string): string;
5
- export declare function getNestedValue(obj: unknown, path: string): unknown;
6
- export declare function asArray<T>(value: T | T[]): T[];
1
+ export { isRecord, getNestedValue } from './object.js';
2
+ export { asArray } from './array.js';
3
+ export { normalizeSiteUrl } from './url.js';
4
+ export { pickFields, pickFieldsSingle, filterData, searchData, sortData, processData, } from './data.js';
@@ -1,37 +1,4 @@
1
- import { ZentaoError } from '../misc/errors.js';
2
- /** 判断值是否为普通对象(非数组、非 null)。 */
3
- export function isRecord(value) {
4
- return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
5
- }
6
- /** 将用户传入的站点根地址规范化,兼容误传入 `/api.php/v2` 的场景。 */
7
- export function normalizeSiteUrl(baseUrl) {
8
- const trimmed = baseUrl.trim().replace(/\/+$/, '');
9
- if (!trimmed)
10
- throw new ZentaoError('E_INVALID_BASE_URL');
11
- const siteUrl = trimmed.replace(/\/api\.php\/v2$/i, '');
12
- let parsed;
13
- try {
14
- parsed = new URL(siteUrl);
15
- }
16
- catch {
17
- throw new ZentaoError('E_INVALID_BASE_URL');
18
- }
19
- if (!['http:', 'https:'].includes(parsed.protocol) || parsed.search || parsed.hash) {
20
- throw new ZentaoError('E_INVALID_BASE_URL');
21
- }
22
- return parsed.toString().replace(/\/+$/, '');
23
- }
24
- export function getNestedValue(obj, path) {
25
- const keys = path.split('.');
26
- let current = obj;
27
- for (const key of keys) {
28
- if (current === null || current === undefined || typeof current !== 'object') {
29
- return undefined;
30
- }
31
- current = current[key];
32
- }
33
- return current;
34
- }
35
- export function asArray(value) {
36
- return Array.isArray(value) ? value : [value];
37
- }
1
+ export { isRecord, getNestedValue } from './object.js';
2
+ export { asArray } from './array.js';
3
+ export { normalizeSiteUrl } from './url.js';
4
+ export { pickFields, pickFieldsSingle, filterData, searchData, sortData, processData, } from './data.js';
@@ -0,0 +1,3 @@
1
+ /** 判断值是否为普通对象(非数组、非 null)。 */
2
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
3
+ export declare function getNestedValue(obj: unknown, path: string): unknown;
@@ -0,0 +1,15 @@
1
+ /** 判断值是否为普通对象(非数组、非 null)。 */
2
+ export function isRecord(value) {
3
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
4
+ }
5
+ export function getNestedValue(obj, path) {
6
+ const keys = path.split('.');
7
+ let current = obj;
8
+ for (const key of keys) {
9
+ if (current === null || current === undefined || typeof current !== 'object') {
10
+ return undefined;
11
+ }
12
+ current = current[key];
13
+ }
14
+ return current;
15
+ }
@@ -0,0 +1,2 @@
1
+ /** 将用户传入的站点根地址规范化,兼容误传入 `/api.php/v2` 的场景。 */
2
+ export declare function normalizeSiteUrl(baseUrl: string): string;
@@ -0,0 +1,19 @@
1
+ import { ZentaoError } from '../misc/errors.js';
2
+ /** 将用户传入的站点根地址规范化,兼容误传入 `/api.php/v2` 的场景。 */
3
+ export function normalizeSiteUrl(baseUrl) {
4
+ const trimmed = baseUrl.trim().replace(/\/+$/, '');
5
+ if (!trimmed)
6
+ throw new ZentaoError('E_INVALID_BASE_URL');
7
+ const siteUrl = trimmed.replace(/\/api\.php\/v2$/i, '');
8
+ let parsed;
9
+ try {
10
+ parsed = new URL(siteUrl);
11
+ }
12
+ catch {
13
+ throw new ZentaoError('E_INVALID_BASE_URL');
14
+ }
15
+ if (!['http:', 'https:'].includes(parsed.protocol) || parsed.search || parsed.hash) {
16
+ throw new ZentaoError('E_INVALID_BASE_URL');
17
+ }
18
+ return parsed.toString().replace(/\/+$/, '');
19
+ }
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
- const fallbackBuild = "2026-05-25T12:42:48.013Z";
2
- const fallbackVersion = "0.2.0";
1
+ const fallbackBuild = "2026-06-27T10:57:52.736Z";
2
+ const fallbackVersion = "0.3.0";
3
3
  /**
4
4
  * 构建标识,由构建脚本通过 `__ZENTAO_API_BUILD__` 注入。
5
5
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zentao-api",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Browser and Node.js SDK for ZenTao API",
6
6
  "license": "MIT",