neo-cmp-cli 1.9.29 → 1.9.30
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.
- package/dist/neo/neoService.js +1 -1
- package/dist/utils/cmpUtils/createCmpByTemplate.js +1 -1
- package/dist/utils/tableLog.js +1 -0
- package/package.json +1 -1
- package/template/neo-custom-cmp-template/src/components/entityForm__c/index.tsx +2 -1
- package/template/neo-custom-cmp-template/src/components/simpleCmp__c/index.tsx +42 -0
- package/template/neo-custom-cmp-template/src/components/simpleCmp__c/model.ts +55 -0
- package/template/neo-custom-cmp-template/src/components/simpleCmp__c/style.scss +21 -0
package/dist/neo/neoService.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("axios"),t=require("form-data"),s=require("node:fs"),o=require("node:path"),i=require("ora"),r=require("lodash"),n=require("akfun"),a=require("./neoLogin.js"),c=require("../utils/projectUtils/updatePublishLog.js"),l=require("../utils/common.js"),h=require("./neoEnvManager.js");var u,d;exports.__require=function(){if(d)return u;d=1;const p=e,m=t,f=s,y=o,w=i,g=r,{resolve:k}=n,A=a.__require(),$=c.__require(),{getFramework:C,errorLog:x,successLog:T}=l.__require(),F=h.__require(),L=["cmpType","label","componentCategory","description","framework","icon","iconUrl","orderNo","version","propsSchema","defaultProps","previewProps","events","functions","asset","modelAsset","cssAsset","codeLib"];return u=class{constructor(){const e=F.getEnvConfig(),{assetsRoot:t,auth:s,authType:o}=e||{};this.authType=o||"oauth2",this.NeoCrmAPI=e,"password"!==this.authType||s||(x("密码授权模式时,neo.config.js / neoConfig / auth 配置不能为空"),process.exit(1)),"password"===this.authType?s.client_id&&s.client_secret&&s.username&&s.password||(x("neo.config.js / neoConfig / auth 配置不完整(password 模式),需要包含 client_id、client_secret、username、password"),process.exit(1)):"oauth2"!=this.authType&&(x(`不支持的授权类型: ${this.authType},可选值:oauth2、password`),process.exit(1)),this.assetsRoot=t||k("dist"),this.auth=s,this.cmpList=[],this.cmpInfoMap={},this.tokenCache={token:null,expiresAt:null}}buildFullUrl(e){return e.startsWith("http://")||e.startsWith("https://")?e:`${this.NeoCrmAPI.neoBaseURL}${e}`}uploadAPI(){return this.buildFullUrl(this.NeoCrmAPI.uploadAPI)}saveAPI(){return this.buildFullUrl(this.NeoCrmAPI.saveAPI)}isTokenExpired(){return!this.tokenCache.token||!this.tokenCache.expiresAt||Date.now()>=this.tokenCache.expiresAt}async getToken(){return this.isTokenExpired()?"oauth2"===this.authType?await this.getTokenByOAuth2():await this.getTokenByPassword():this.tokenCache.token}async getTokenByPassword(){const e=w("获取 token(密码模式)...").start();if(!this.isTokenExpired())return T("使用缓存的 token。",e),this.tokenCache.token;const t=new URLSearchParams;t.append("grant_type","password"),t.append("client_id",this.auth.client_id),t.append("client_secret",this.auth.client_secret),t.append("username",this.auth.username),t.append("password",this.auth.password);const s=this.buildFullUrl(this.NeoCrmAPI.tokenURL);try{const o=await p.post(s,t.toString(),{headers:{"Content-Type":"application/x-www-form-urlencoded"}}),i=o.data||{},{access_token:r,expires_in:n}=i;r||(x("获取 token 失败(授权配置错误):响应中未包含 access_token,"+JSON.stringify(o.data),e),process.exit(1));const a=parseInt(n)||3600;return this.tokenCache={...i,token:r,expiresAt:Date.now()+1e3*(a-60)},e.clear(),e.stop(),r}catch(o){x("获取 token 失败",e),x(`\n获取 token 失败: ${o.message||o.msg}`),x(`\ntoken 授权地址: ${s}`),x(`\ntoken 请求参数: ${t}`),o.response&&x(`响应数据: ${JSON.stringify(o.response.data)}`),process.exit(1)}}async getTokenByOAuth2(){const e=w("获取 token(OAuth2 模式)...").start();try{const t={loginURL:this.NeoCrmAPI.loginURL,tokenURL:this.NeoCrmAPI.tokenURL},s=new A(t),o=await s.getAccessToken(),i=o.access_token;return this.tokenCache={...o,token:i,expiresAt:Date.now()+72e5},e.clear(),e.stop(),i}catch(t){x("获取 token 失败(OAuth2 模式)",e),x(`\n获取 token 失败: ${t.message||t.msg}`),t.response&&x(`响应数据: ${JSON.stringify(t.response.data)}`),process.exit(1)}}async refreshToken(){return this.tokenCache={token:null,expiresAt:null},await this.getToken()}async ensureValidToken(){if(!this.tokenCache.token)return await this.getToken();if(this.isTokenExpired()){const e=w("token 已过期,正在刷新...").start();try{const t=await this.refreshToken();return T("token 刷新成功。",e),t}catch(t){throw x("token 刷新失败。",e),t}}return this.tokenCache.token}async uploadFile(e,t={}){const s=await this.ensureValidToken();if(!e||"string"!=typeof e)throw new Error(`文件路径无效: ${e}`);if(!f.existsSync(e))throw new Error(`文件不存在: ${e}`);const o=f.statSync(e);if(!o.isFile())throw new Error(`路径不是文件: ${e}`);const i=t.maxSize||5242880;if(o.size>i){const e=(o.size/1024/1024).toFixed(2),t=(i/1024/1024).toFixed(2);throw new Error(`文件大小超过限制: ${e}MB > ${t}MB`)}if(0===o.size)throw new Error(`文件为空: ${e}`);const r=y.basename(e),n=(o.size/1024).toFixed(2),a=w(`正在上传文件: ${r} (${n}KB)...`).start();try{const o=new m,i=t.fieldName||"customComponentCode",n=f.createReadStream(e);o.append(i,n,r);const c=this.uploadAPI(),l=t.timeout||6e4,h={headers:{Authorization:`Bearer ${s}`,"xsy-inner-source":"bff",...o.getHeaders()},timeout:l,maxContentLength:1/0,maxBodyLength:1/0},u=await p.post(c,o,h);let d;const y=u.data;if(200!==u.status&&201!==u.status)throw new Error(`上传失败: HTTP ${u.status}`);if("string"==typeof y)d=y.trim();else{if(!y||"object"!=typeof y)throw new Error("响应数据格式不正确: "+typeof y);if(void 0!==y.code&&200!==y.code&&0!==y.code){const e=y.message||y.msg||"未知错误";throw new Error(`上传失败: ${e} (code: ${y.code})`)}d=void 0!==y.data?y.data:void 0!==y.url?y.url:void 0!==y.fileUrl?y.fileUrl:y}if(!d)throw new Error("返回的文件地址为空");let w;return"string"==typeof d?w=d:d&&"object"==typeof d&&d.url&&(w=d.url),T(`文件上传成功: ${r} -> ${w}`,a),w}catch(t){if(x(`上传文件失败: ${t.message||t.msg}, 文件路径: ${e}`,a),t.response){const e=t.response.status,s=t.response.statusText,o=t.response.data,i=t.config?.url||this.uploadAPI();if(x("\n========== 上传请求详情 =========="),x(`请求 URL: ${i}`),x(`HTTP 状态码: ${e} ${s}`),x(`响应数据: ${JSON.stringify(o)}`),x("==================================\n"),404===e)throw new Error(`上传 API 不存在 (404): ${i}\n请检查 neo.config.js 中的 neoBaseURL 配置是否正确,或者 API 路径是否存在。\n当前配置的 API 路径: ${this.NeoCrmAPI.uploadAPI}`)}else t.request&&x("请求已发送但未收到响应,请检查网络连接或代理配置。");throw t}}async publish2oss(e,t=[".js",".css",".zip"]){if(!e)return void x(`自定义组件名称不能为空: ${e}`);if(!f.existsSync(this.assetsRoot))return void x(`未找到自定义组件资源目录: ${this.assetsRoot}`);const s={cmpType:e},o=f.readdirSync(this.assetsRoot).map(async o=>{const i=y.join(this.assetsRoot,o),r=f.statSync(i),n=y.parse(i);if(r.isFile()&&t.includes(n.ext)){let t=g.camelCase(e);if(o.indexOf(t)<0)return;try{const e=await this.uploadFile(i);o.indexOf("Model")>-1?s.modelAsset=e:o.endsWith(".css")?s.cssAsset=e:o.endsWith(".zip")?s.codeLib=e:s.asset=e}catch(e){x(`文件上传失败(${o}):\n`),process.exit(1)}}});return await Promise.all(o),s&&s.cmpType&&(console.info("上传至 OSS 的文件信息:\n",s),$(s)),s}async getCmpAssets(e,t=[".js",".css",".zip"]){if(!e)return void x(`自定义组件名称不能为空: ${e}`);if(!f.existsSync(this.assetsRoot))return void x(`未找到自定义组件资源目录: ${this.assetsRoot}`);const s={cmpType:e};return f.readdirSync(this.assetsRoot).forEach(o=>{const i=y.join(this.assetsRoot,o),r=f.statSync(i),n=y.parse(i);if(r.isFile()&&t.includes(n.ext)){let t=g.camelCase(e);if(o.indexOf(t)<0)return;const n=5242880;if(r.size>n){const e=(r.size/1024/1024).toFixed(2),t=(n/1024/1024).toFixed(2);throw new Error(`${o} 文件大小超过限制: ${e}MB > ${t}MB`)}const a={fileContent:f.createReadStream(i),fileName:o,fileSize:r.size};o.indexOf("Model")>-1?s.modelAssetFile=a:o.endsWith(".css")?s.cssAssetFile=a:o.endsWith(".zip")?s.codeLibFile=a:s.assetFile=a}}),s}async updateCustomComponent(e){const t=await this.ensureValidToken();if(!e)throw new Error("componentData 不能为空");const s=w("正在保存自定义组件信息...").start();try{const o=this.saveAPI(),i=new m;e.assetFile&&i.append("assetFile",e.assetFile.fileContent,e.assetFile.fileName),e.modelAssetFile&&i.append("modelAssetFile",e.modelAssetFile.fileContent,e.modelAssetFile.fileName),e.cssAssetFile&&i.append("cssAssetFile",e.cssAssetFile.fileContent,e.cssAssetFile.fileName),e.codeLibFile&&i.append("codeLibFile",e.codeLibFile.fileContent,e.codeLibFile.fileName),i.append("component",JSON.stringify(g.omit(e,["assetFile","modelAssetFile","cssAssetFile","codeLibFile"])));const r=await p.post(o,i,{headers:{Authorization:`Bearer ${t}`,"xsy-inner-source":"bff",...i.getHeaders()},timeout:12e4,maxContentLength:1/0,maxBodyLength:1/0}),{code:n,message:a,msg:c}=r.data||{};n&&200!==n&&(x(`保存自定义组件信息失败: ${a||c||"未知错误"}`),process.exit(1)),s.clear(),s.stop()}catch(e){const t=e.message||e.msg;x(t?`保存自定义组件信息失败: ${t}`:`保存自定义组件信息失败: ${JSON.stringify(e)}`,s),process.exit(1)}}async getCustomCmpList(){const e=await this.ensureValidToken();try{let t=this.buildFullUrl(this.NeoCrmAPI.queryAll);t+=`&fields=${L.join(",")}`;const s=await p.get(t,{headers:{Authorization:`Bearer ${e}`,"xsy-inner-source":"bff","Content-Type":"application/json"}}),{code:o,message:i,msg:r}=s.data||{};o&&200!==o&&(x(`获取自定义组件列表失败: ${i||r||"未知错误"}`),process.exit(1)),this.updateCustomCmpList(s.data.data||[])}catch(e){const t=e.message||e.msg;x(t?`获取自定义组件列表失败: ${t}`:`响应数据: ${JSON.stringify(e)}`),process.exit(1)}return this.cmpList||[]}getCodeLibByCmpType(e){return e?this.buildFullUrl(this.NeoCrmAPI.getCodeLibAPI(e)):null}async deleteCmp(e){const t=await this.ensureValidToken();e||(x("自定义组件名称不能为空。"),process.exit(1));let s=this.buildFullUrl(this.NeoCrmAPI.delete);s+=`/${e}`;const o=await p.delete(s,{headers:{Authorization:`Bearer ${t}`,"xsy-inner-source":"bff","Content-Type":"application/json"}}),{code:i,message:r,msg:n}=o.data||{};return i&&200!==i&&(x(`删除自定义组件失败: ${r||n||"未知错误"}`),process.exit(1)),o.data}getCmpListByFramework(e){if(!e)return this.cmpList;const t=C(e);return this.cmpList.filter(e=>e.framework===t)}getCmpInfoByCmpType(e){return e&&this.cmpInfoMap[e]||null}updateCustomCmpList(e){e&&Array.isArray(e)&&(this.cmpList=e,e.forEach(e=>{this.cmpInfoMap[e.cmpType]=e}))}async request(e,t,s={}){const o=await this.ensureValidToken(),{data:i,headers:r={},params:n}=s,a=this.buildFullUrl(t);try{const t=await p({method:e,url:a,data:i,params:n,headers:{Authorization:`Bearer ${o}`,"xsy-inner-source":"bff",...r}});if(t.data&&t.data.code&&200!==t.data.code)throw new Error(`请求失败: ${t.data.message||t.data.msg||"未知错误"}`);return t.data}catch(s){throw x(`请求失败 [${e} ${t}]: ${s.message||s.msg}`),s.response&&x(`响应数据: ${JSON.stringify(s.response.data)}`),s}}async get(e,t={}){return await this.request("GET",e,t)}async post(e,t={}){return await this.request("POST",e,t)}async put(e,t={}){return await this.request("PUT",e,t)}async delete(e,t={}){return await this.request("DELETE",e,t)}}};
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("axios"),t=require("form-data"),s=require("node:fs"),o=require("node:path"),i=require("ora"),r=require("lodash"),n=require("akfun"),a=require("./neoLogin.js"),c=require("../utils/projectUtils/updatePublishLog.js"),l=require("../utils/common.js"),h=require("./neoEnvManager.js"),u=require("../utils/tableLog.js");var d,p;exports.__require=function(){if(p)return d;p=1;const m=e,f=t,y=s,g=o,w=i,k=r,{resolve:A}=n,$=a.__require(),C=c.__require(),{getFramework:x,errorLog:T,successLog:F}=l.__require(),L=h.__require(),P=u.__require(),b=["cmpType","label","componentCategory","description","framework","icon","iconUrl","orderNo","version","propsSchema","defaultProps","previewProps","events","functions","asset","modelAsset","cssAsset","codeLib"];return d=class{constructor(){const e=L.getEnvConfig(),{assetsRoot:t,auth:s,authType:o}=e||{};this.authType=o||"oauth2",this.NeoCrmAPI=e,"password"!==this.authType||s||(T("密码授权模式时,neo.config.js / neoConfig / auth 配置不能为空"),process.exit(1)),"password"===this.authType?s.client_id&&s.client_secret&&s.username&&s.password||(T("neo.config.js / neoConfig / auth 配置不完整(password 模式),需要包含 client_id、client_secret、username、password"),process.exit(1)):"oauth2"!=this.authType&&(T(`不支持的授权类型: ${this.authType},可选值:oauth2、password`),process.exit(1)),this.assetsRoot=t||A("dist"),this.auth=s,this.cmpList=[],this.cmpInfoMap={},this.tokenCache={token:null,expiresAt:null}}buildFullUrl(e){return e.startsWith("http://")||e.startsWith("https://")?e:`${this.NeoCrmAPI.neoBaseURL}${e}`}uploadAPI(){return this.buildFullUrl(this.NeoCrmAPI.uploadAPI)}saveAPI(){return this.buildFullUrl(this.NeoCrmAPI.saveAPI)}isTokenExpired(){return!this.tokenCache.token||!this.tokenCache.expiresAt||Date.now()>=this.tokenCache.expiresAt}async getToken(){return this.isTokenExpired()?"oauth2"===this.authType?await this.getTokenByOAuth2():await this.getTokenByPassword():this.tokenCache.token}async getTokenByPassword(){const e=w("获取 token(密码模式)...").start();if(!this.isTokenExpired())return F("使用缓存的 token。",e),this.tokenCache.token;const t=new URLSearchParams;t.append("grant_type","password"),t.append("client_id",this.auth.client_id),t.append("client_secret",this.auth.client_secret),t.append("username",this.auth.username),t.append("password",this.auth.password);const s=this.buildFullUrl(this.NeoCrmAPI.tokenURL);try{const o=await m.post(s,t.toString(),{headers:{"Content-Type":"application/x-www-form-urlencoded"}}),i=o.data||{},{access_token:r,expires_in:n}=i;r||(T("获取 token 失败(授权配置错误):响应中未包含 access_token,"+JSON.stringify(o.data),e),process.exit(1));const a=parseInt(n)||3600;return this.tokenCache={...i,token:r,expiresAt:Date.now()+1e3*(a-60)},e.clear(),e.stop(),r}catch(o){T("获取 token 失败",e),T(`\n获取 token 失败: ${o.message||o.msg}`),T(`\ntoken 授权地址: ${s}`),T(`\ntoken 请求参数: ${t}`),o.response&&T(`响应数据: ${JSON.stringify(o.response.data)}`),process.exit(1)}}async getTokenByOAuth2(){const e=w("获取 token(OAuth2 模式)...").start();try{const t={loginURL:this.NeoCrmAPI.loginURL,tokenURL:this.NeoCrmAPI.tokenURL},s=new $(t),o=await s.getAccessToken(),i=o.access_token;return this.tokenCache={...o,token:i,expiresAt:Date.now()+72e5},e.clear(),e.stop(),i}catch(t){T("获取 token 失败(OAuth2 模式)",e),T(`\n获取 token 失败: ${t.message||t.msg}`),t.response&&T(`响应数据: ${JSON.stringify(t.response.data)}`),process.exit(1)}}async refreshToken(){return this.tokenCache={token:null,expiresAt:null},await this.getToken()}async ensureValidToken(){if(!this.tokenCache.token)return await this.getToken();if(this.isTokenExpired()){const e=w("token 已过期,正在刷新...").start();try{const t=await this.refreshToken();return F("token 刷新成功。",e),t}catch(t){throw T("token 刷新失败。",e),t}}return this.tokenCache.token}async uploadFile(e,t={}){const s=await this.ensureValidToken();if(!e||"string"!=typeof e)throw new Error(`文件路径无效: ${e}`);if(!y.existsSync(e))throw new Error(`文件不存在: ${e}`);const o=y.statSync(e);if(!o.isFile())throw new Error(`路径不是文件: ${e}`);const i=t.maxSize||5242880;if(o.size>i){const e=(o.size/1024/1024).toFixed(2),t=(i/1024/1024).toFixed(2);throw new Error(`文件大小超过限制: ${e}MB > ${t}MB`)}if(0===o.size)throw new Error(`文件为空: ${e}`);const r=g.basename(e),n=(o.size/1024).toFixed(2),a=w(`正在上传文件: ${r} (${n}KB)...`).start();try{const o=new f,i=t.fieldName||"customComponentCode",n=y.createReadStream(e);o.append(i,n,r);const c=this.uploadAPI(),l=t.timeout||6e4,h={headers:{Authorization:`Bearer ${s}`,"xsy-inner-source":"bff",...o.getHeaders()},timeout:l,maxContentLength:1/0,maxBodyLength:1/0},u=await m.post(c,o,h);let d;const p=u.data;if(200!==u.status&&201!==u.status)throw new Error(`上传失败: HTTP ${u.status}`);if("string"==typeof p)d=p.trim();else{if(!p||"object"!=typeof p)throw new Error("响应数据格式不正确: "+typeof p);if(void 0!==p.code&&200!==p.code&&0!==p.code){const e=p.message||p.msg||"未知错误";throw new Error(`上传失败: ${e} (code: ${p.code})`)}d=void 0!==p.data?p.data:void 0!==p.url?p.url:void 0!==p.fileUrl?p.fileUrl:p}if(!d)throw new Error("返回的文件地址为空");let g;return"string"==typeof d?g=d:d&&"object"==typeof d&&d.url&&(g=d.url),F(`文件上传成功: ${r} -> ${g}`,a),g}catch(t){if(T(`上传文件失败: ${t.message||t.msg}, 文件路径: ${e}`,a),t.response){const e=t.response.status,s=t.response.statusText,o=t.response.data,i=t.config?.url||this.uploadAPI();if(T("\n========== 上传请求详情 =========="),T(`请求 URL: ${i}`),T(`HTTP 状态码: ${e} ${s}`),T(`响应数据: ${JSON.stringify(o)}`),T("==================================\n"),404===e)throw new Error(`上传 API 不存在 (404): ${i}\n请检查 neo.config.js 中的 neoBaseURL 配置是否正确,或者 API 路径是否存在。\n当前配置的 API 路径: ${this.NeoCrmAPI.uploadAPI}`)}else t.request&&T("请求已发送但未收到响应,请检查网络连接或代理配置。");throw t}}async publish2oss(e,t=[".js",".css",".zip"]){if(!e)return void T(`自定义组件名称不能为空: ${e}`);if(!y.existsSync(this.assetsRoot))return void T(`未找到自定义组件资源目录: ${this.assetsRoot}`);const s={cmpType:e},o=y.readdirSync(this.assetsRoot).map(async o=>{const i=g.join(this.assetsRoot,o),r=y.statSync(i),n=g.parse(i);if(r.isFile()&&t.includes(n.ext)){let t=k.camelCase(e);if(o.indexOf(t)<0)return;try{const e=await this.uploadFile(i);o.indexOf("Model")>-1?s.modelAsset=e:o.endsWith(".css")?s.cssAsset=e:o.endsWith(".zip")?s.codeLib=e:s.asset=e}catch(e){T(`文件上传失败(${o}):\n`),process.exit(1)}}});return await Promise.all(o),s&&s.cmpType&&(console.info("上传至 OSS 的文件信息:\n",s),C(s)),s}async getCmpAssets(e,t=[".js",".css",".zip"]){if(!e)return void T(`自定义组件名称不能为空: ${e}`);if(!y.existsSync(this.assetsRoot))return void T(`未找到自定义组件资源目录: ${this.assetsRoot}`);const s={cmpType:e};return y.readdirSync(this.assetsRoot).forEach(o=>{const i=g.join(this.assetsRoot,o),r=y.statSync(i),n=g.parse(i);if(r.isFile()&&t.includes(n.ext)){let t=k.camelCase(e);if(o.indexOf(t)<0)return;const n=5242880;if(r.size>n){const e=(r.size/1024/1024).toFixed(2),t=(n/1024/1024).toFixed(2);throw new Error(`${o} 文件大小超过限制: ${e}MB > ${t}MB`)}const a={fileContent:y.createReadStream(i),fileName:o,fileSize:r.size};o.indexOf("Model")>-1?s.modelAssetFile=a:o.endsWith(".css")?s.cssAssetFile=a:o.endsWith(".zip")?s.codeLibFile=a:s.assetFile=a}}),s}async updateCustomComponent(e){const t=await this.ensureValidToken();if(!e)throw new Error("componentData 不能为空");const s=w("正在保存自定义组件信息...").start();try{const o=this.saveAPI(),i=new f;e.assetFile&&i.append("assetFile",e.assetFile.fileContent,e.assetFile.fileName),e.modelAssetFile&&i.append("modelAssetFile",e.modelAssetFile.fileContent,e.modelAssetFile.fileName),e.cssAssetFile&&i.append("cssAssetFile",e.cssAssetFile.fileContent,e.cssAssetFile.fileName),e.codeLibFile&&i.append("codeLibFile",e.codeLibFile.fileContent,e.codeLibFile.fileName),i.append("component",JSON.stringify(k.omit(e,["assetFile","modelAssetFile","cssAssetFile","codeLibFile"])));const r=await m.post(o,i,{headers:{Authorization:`Bearer ${t}`,"xsy-inner-source":"bff",...i.getHeaders()},timeout:12e4,maxContentLength:1/0,maxBodyLength:1/0}),{code:n,message:a,msg:c}=r.data||{};n&&200!==n&&(T(`保存自定义组件信息失败: ${a||c||"未知错误"}`),process.exit(1)),s.clear(),s.stop()}catch(e){const t=e.message||e.msg;T(t?`保存自定义组件信息失败: ${t}`:`保存自定义组件信息失败: ${JSON.stringify(e)}`,s),process.exit(1)}}async getCustomCmpList(){const e=await this.ensureValidToken();try{let t=this.buildFullUrl(this.NeoCrmAPI.queryAll);t+=`&fields=${b.join(",")}`;const s=await m.get(t,{headers:{Authorization:`Bearer ${e}`,"xsy-inner-source":"bff","Content-Type":"application/json"}}),{code:o,message:i,msg:r}=s.data||{};o&&200!==o&&(T(`获取自定义组件列表失败: ${i||r||"未知错误"}`),process.exit(1)),this.updateCustomCmpList(s.data.data||[])}catch(e){const t=e.message||e.msg;T(t?`获取自定义组件列表失败: ${t}`:`响应数据: ${JSON.stringify(e)}`),process.exit(1)}return this.cmpList||[]}getCodeLibByCmpType(e){return e?this.buildFullUrl(this.NeoCrmAPI.getCodeLibAPI(e)):null}async deleteCmp(e){const t=await this.ensureValidToken();e||(T("自定义组件名称不能为空。"),process.exit(1));let s=this.buildFullUrl(this.NeoCrmAPI.delete);s+=`/${e}`;const o=await m.delete(s,{headers:{Authorization:`Bearer ${t}`,"xsy-inner-source":"bff","Content-Type":"application/json"}}),{code:i,message:r,msg:n,errorInfo:a}=o.data||{};return i&&200!==i&&(a&&a.length>0?P(a,{title:"删除自定义组件失败",columns:["reason","instance"],headers:{name:"原因",age:"实例"},align:{name:"left",city:"center"},padding:2,showBorder:!0}):T(`删除自定义组件失败: ${r||n||"未知错误"}`),process.exit(1)),o.data}getCmpListByFramework(e){if(!e)return this.cmpList;const t=x(e);return this.cmpList.filter(e=>e.framework===t)}getCmpInfoByCmpType(e){return e&&this.cmpInfoMap[e]||null}updateCustomCmpList(e){e&&Array.isArray(e)&&(this.cmpList=e,e.forEach(e=>{this.cmpInfoMap[e.cmpType]=e}))}async request(e,t,s={}){const o=await this.ensureValidToken(),{data:i,headers:r={},params:n}=s,a=this.buildFullUrl(t);try{const t=await m({method:e,url:a,data:i,params:n,headers:{Authorization:`Bearer ${o}`,"xsy-inner-source":"bff",...r}});if(t.data&&t.data.code&&200!==t.data.code)throw new Error(`请求失败: ${t.data.message||t.data.msg||"未知错误"}`);return t.data}catch(s){throw T(`请求失败 [${e} ${t}]: ${s.message||s.msg}`),s.response&&T(`响应数据: ${JSON.stringify(s.response.data)}`),s}}async get(e,t={}){return await this.request("GET",e,t)}async post(e,t={}){return await this.request("POST",e,t)}async put(e,t={}){return await this.request("PUT",e,t)}async delete(e,t={}){return await this.request("DELETE",e,t)}}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("fs-extra"),r=require("node:path"),o=require("lodash"),s=require("../neoParams.js"),c=require("../replaceInFilesByMap.js"),i=require("./hasCmpTypeByDir.js"),t=require("../projectUtils/hasNeoProject.js"),n=require("../cmpTypeValidator.js"),m=require("../common.js");var p,a;exports.__require=function(){if(a)return p;a=1;const u=e,l=r,d=o,{consoleTag:_}=s.__require(),q=c.__require(),f=i.__require(),x=t.__require(),{validateApiName:g,ensureApiNameSuffix:j,removeApiNameSuffix:y}=n.__require(),{errorLog:N}=m.__require(),$={widgetInfo:{cmpName:"CustomCmp",modelName:"CmpModel",cmpClassName:"custom-cmp-container",cmpType:"xx-custom-cmp",cmpLabel:"xx组件"},dir:l.resolve(__dirname,"../../../template/empty-cmp")};return p=function(e,r="./src/components"){const o=$.dir;let s=e||"neoCustomCmp__c";s=j(s);const{isValid:c,errors:i}=g(s);c||(N(i.join("\n")),process.exit(1));const t=l.resolve(process.cwd(),r,s);x()||(console.error(`${_}当前(${process.cwd()})还不是自定义组件项目,请先创建一个自定义组件项目(neo init / neo create project)。`),process.exit(1)),f(s)&&(console.error(`${_}创建自定义组件失败,当前项目已经存在${s}自定义组件。`),process.exit(1)),u.copy(o,t).then(()=>{const e=d.camelCase(y(s)),r=s;q(t,{[$.widgetInfo.modelName]:`${e}Model`,[$.widgetInfo.cmpName]:e,[$.widgetInfo.cmpClassName]:`${r}-container`,[$.widgetInfo.cmpType]:r,[$.widgetInfo.cmpLabel]:
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("fs-extra"),r=require("node:path"),o=require("lodash"),s=require("../neoParams.js"),c=require("../replaceInFilesByMap.js"),i=require("./hasCmpTypeByDir.js"),t=require("../projectUtils/hasNeoProject.js"),n=require("../cmpTypeValidator.js"),m=require("../common.js");var p,a;exports.__require=function(){if(a)return p;a=1;const u=e,l=r,d=o,{consoleTag:_}=s.__require(),q=c.__require(),f=i.__require(),x=t.__require(),{validateApiName:g,ensureApiNameSuffix:j,removeApiNameSuffix:y}=n.__require(),{errorLog:N}=m.__require(),$={widgetInfo:{cmpName:"CustomCmp",modelName:"CmpModel",cmpClassName:"custom-cmp-container",cmpType:"xx-custom-cmp",cmpLabel:"xx组件"},dir:l.resolve(__dirname,"../../../template/empty-cmp")};return p=function(e,r="./src/components"){const o=$.dir;let s=e||"neoCustomCmp__c";s=j(s);const{isValid:c,errors:i}=g(s);c||(N(i.join("\n")),process.exit(1));const t=l.resolve(process.cwd(),r,s);x()||(console.error(`${_}当前(${process.cwd()})还不是自定义组件项目,请先创建一个自定义组件项目(neo init / neo create project)。`),process.exit(1)),f(s)&&(console.error(`${_}创建自定义组件失败,当前项目已经存在${s}自定义组件。`),process.exit(1)),u.copy(o,t).then(()=>{const e=d.camelCase(y(s)),r=s;q(t,{[$.widgetInfo.modelName]:`${e}Model`,[$.widgetInfo.cmpName]:e,[$.widgetInfo.cmpClassName]:`${r}-container`,[$.widgetInfo.cmpType]:r,[$.widgetInfo.cmpLabel]:e}),console.log(`${_}已创建自定义组件(${s})!`)}).catch(e=>console.error(`${_}自定义组件创建失败(${s}):`,e))}};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("chalk"),r=require("./neoParams.js");var o,n;exports.__require=function(){if(n)return o;n=1;const t=e,{consoleTag:l}=r.__require();function c(e,r,o,n){const t=function(e){const r=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;return e.replace(r,"").length}(e),l=r-2*n,c=" ".repeat(n);if(t>=l)return c+e.slice(0,l)+c;const a=l-t;switch(o){case"right":return c+" ".repeat(a)+e+c;case"center":const r=Math.floor(a/2),o=a-r;return c+" ".repeat(r)+e+" ".repeat(o)+c;default:return c+e+" ".repeat(a)+c}}return o={tableLog:function(e,r={}){if(!Array.isArray(e)||0===e.length)return void console.log(`${l} ${t.yellow("警告: 数据为空或格式不正确")}`);const{columns:o,headers:n={},align:a={},padding:s=1,showBorder:g=!0,title:i}=r,u=(o||Object.keys(e[0])).filter(e=>!o||o.includes(e));if(0===u.length)return void console.log(`${l} ${t.yellow("警告: 没有可显示的列")}`);const $={};u.forEach(r=>{const o=n[r]||r;let t=String(o).length;e.forEach(e=>{const o=e[r],n=null!=o?String(o):"";t=Math.max(t,n.length)}),$[r]=t+2*s});const y=g?t.gray("─".repeat(u.reduce((e,r)=>e+$[r]+3,1))):"";i&&console.log(`${l} ${t.cyan.bold(i)}`),g&&y&&console.log(`${l} ${t.gray("┌")}${y.slice(1,-1)}${t.gray("┐")}`);const f=u.map((e,r)=>{const o=c(n[e]||e,$[e],a[e]||"left",s);return t.bold.cyan(o)}).join(g?t.gray(" │ "):" ");console.log(`${l} ${g?t.gray("│ "):""}${f}${g?t.gray(" │"):""}`),g&&y&&console.log(`${l} ${t.gray("├")}${y.slice(1,-1).replace(/─/g,"─")}${t.gray("┤")}`),e.forEach((e,r)=>{const o=u.map((r,o)=>{const n=e[r];return c(null!=n?String(n):"",$[r],a[r]||"left",s)}).join(g?t.gray(" │ "):" ");console.log(`${l} ${g?t.gray("│ "):""}${o}${g?t.gray(" │"):""}`)}),g&&y&&console.log(`${l} ${t.gray("└")}${y.slice(1,-1)}${t.gray("┘")}`)}}};
|
package/package.json
CHANGED
|
@@ -157,6 +157,7 @@ export default class EntityForm extends React.PureComponent<
|
|
|
157
157
|
} else {
|
|
158
158
|
this.setState({
|
|
159
159
|
fieldList: [],
|
|
160
|
+
error: null,
|
|
160
161
|
});
|
|
161
162
|
}
|
|
162
163
|
}
|
|
@@ -189,7 +190,7 @@ export default class EntityForm extends React.PureComponent<
|
|
|
189
190
|
async loadFieldList() {
|
|
190
191
|
const { xObjectDataApi } = this.props || {};
|
|
191
192
|
|
|
192
|
-
this.setState({ loading: true });
|
|
193
|
+
this.setState({ loading: true, error: null });
|
|
193
194
|
|
|
194
195
|
try {
|
|
195
196
|
// 方式一:直接从 props.xObjectDataApi 中获取字段描述
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
// 引入 neo-ui-common / BaseCmp
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import { BaseCmp } from 'neo-ui-common';
|
|
5
|
+
import './style.scss'; // 组件内容样式
|
|
6
|
+
|
|
7
|
+
interface CustomCmpProps {
|
|
8
|
+
description: string;
|
|
9
|
+
data?: any;
|
|
10
|
+
env?: any;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface CustomCmpStates {
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default class CustomCmp extends BaseCmp<CustomCmpProps, CustomCmpStates> {
|
|
19
|
+
constructor(props: CustomCmpProps) {
|
|
20
|
+
super(props);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
render() {
|
|
24
|
+
const { description, className, env } = this.props;
|
|
25
|
+
const ctx = (env || {}).ctx;
|
|
26
|
+
let languageCode = 'zh-CN'; // 默认中文
|
|
27
|
+
// 从上下文中 获取系统语言
|
|
28
|
+
if (ctx && ctx.system && ctx.system.language) {
|
|
29
|
+
languageCode = ctx.system.language;
|
|
30
|
+
}
|
|
31
|
+
console.log('当前自定义组件:', this.props);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div className={`custom-cmp-container ${className}`}>
|
|
35
|
+
<div className="news-title">
|
|
36
|
+
{languageCode === 'zh-CN' ? '你好,销售易!' : 'Hello NeoCRM!'}
|
|
37
|
+
</div>
|
|
38
|
+
<p>{description}</p>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 自定义组件对接编辑器的描述文件
|
|
3
|
+
*/
|
|
4
|
+
export class CmpModel {
|
|
5
|
+
// 组件名称,用于设置在编辑器左侧组件面板中展示的名称
|
|
6
|
+
label: string = '简单示例组件';
|
|
7
|
+
|
|
8
|
+
// 组件描述,用于设置在编辑器左侧组件面板中展示的描述
|
|
9
|
+
description: string = '暂无描述';
|
|
10
|
+
|
|
11
|
+
// 分类标签,用于设置在编辑器左侧组件面板哪个分类中展示
|
|
12
|
+
// tags: string[] = ['自定义组件'];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 用于设置组件支持的页面类型
|
|
16
|
+
*
|
|
17
|
+
* 当前 NeoCRM 平台存在的页面类型:
|
|
18
|
+
* all: 1 全页面
|
|
19
|
+
* entityFormPage: 4 实体表单页
|
|
20
|
+
* customPage: 6 自定义页面
|
|
21
|
+
*/
|
|
22
|
+
targetPage: string[] = ['all'];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 用于设置组件支持的终端类型
|
|
26
|
+
*
|
|
27
|
+
* 当前 NeoCRM 平台存在的终端类型:
|
|
28
|
+
* web: 网页端
|
|
29
|
+
* mobile: 移动端
|
|
30
|
+
*/
|
|
31
|
+
// targetDevice: string = 'web';
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
// 组件图标,用于设置在编辑器左侧组件面板中展示的图标
|
|
35
|
+
iconUrl: string = 'https://neo-widgets.bj.bcebos.com/custom-widget.svg';
|
|
36
|
+
|
|
37
|
+
// 初次插入页面的默认属性数据
|
|
38
|
+
defaultComProps = {
|
|
39
|
+
description: '营销服全场景智能CRM,帮助企业搭建数字化客户经营平台,实现业绩高质量增长。'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 组件面板配置,用于生成编辑器右侧属性配置面板内容
|
|
44
|
+
*/
|
|
45
|
+
propsSchema = [
|
|
46
|
+
{
|
|
47
|
+
type: 'textarea',
|
|
48
|
+
name: 'description',
|
|
49
|
+
label: '组件内容',
|
|
50
|
+
value: '',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default CmpModel;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--padding-bottom: 12px;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.custom-cmp-container {
|
|
6
|
+
position: relative;
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
|
|
9
|
+
/* border-bottom: 1px solid #ececec; */
|
|
10
|
+
margin: 6px 12px;
|
|
11
|
+
padding: 6px var(--padding-bottom);
|
|
12
|
+
background-color: #fff;
|
|
13
|
+
|
|
14
|
+
.news-title {
|
|
15
|
+
padding: 6px 0;
|
|
16
|
+
font-family: PingFangSC-Regular;
|
|
17
|
+
font-size: 16px;
|
|
18
|
+
line-height: 22px;
|
|
19
|
+
color: #5f5e5e;
|
|
20
|
+
}
|
|
21
|
+
}
|