Compare commits
2 Commits
fe5dc9df34
...
95f5b75a1a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
95f5b75a1a | ||
![]() |
c828d3cdbc |
24
pom.xml
24
pom.xml
@ -53,9 +53,33 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.14</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>5.8.32</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
<artifactId>fastjson2</artifactId>
|
||||||
|
<version>2.0.53</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpmime</artifactId>
|
||||||
|
<version>4.5.13</version> <!-- 请根据需要使用最新版本 -->
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
<finalName>collabora-api</finalName>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import vin.vio.collaboraonline.model.WopiFile;
|
import vin.vio.collaboraonline.model.WopiFile;
|
||||||
import vin.vio.collaboraonline.service.FileService;
|
import vin.vio.collaboraonline.service.FileService;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -48,9 +49,9 @@ public class WopiController {
|
|||||||
|
|
||||||
// 获取文件内容
|
// 获取文件内容
|
||||||
@GetMapping("/files/{fileId}/contents")
|
@GetMapping("/files/{fileId}/contents")
|
||||||
public ResponseEntity<Resource> getFile(@PathVariable String fileId) {
|
public ResponseEntity<File> getFile(@PathVariable String fileId) {
|
||||||
|
|
||||||
org.springframework.core.io.Resource fileResource = fileService.loadFileAsResource(fileId);
|
File fileResource = fileService.loadFileAsResource(fileId);
|
||||||
if (fileResource == null) {
|
if (fileResource == null) {
|
||||||
return ResponseEntity.notFound().build();
|
return ResponseEntity.notFound().build();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package vin.vio.collaboraonline.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @Date: 2025/2/21 16:24
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AllKingdeeException extends Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
public AllKingdeeException(String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
187
src/main/java/vin/vio/collaboraonline/kingdee/AuthService.java
Normal file
187
src/main/java/vin/vio/collaboraonline/kingdee/AuthService.java
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
package vin.vio.collaboraonline.kingdee;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import org.apache.http.Header;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||||
|
import org.apache.http.entity.mime.MultipartEntity;
|
||||||
|
import org.apache.http.entity.mime.content.InputStreamBody;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import vin.vio.collaboraonline.exception.AllKingdeeException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @Date: 2025/2/21 16:25
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AuthService {
|
||||||
|
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.is-public}")
|
||||||
|
private Boolean isPublic;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.test-public-end-point}")
|
||||||
|
private String testPublicEndPoint;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.test-inner-end-point}")
|
||||||
|
private String testInnerEndPoint;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.prod-public-end-point}")
|
||||||
|
private String prodPublicEndPoint;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.prod-inner-end-point}")
|
||||||
|
private String prodInnerEndPoint;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.env}")
|
||||||
|
private String env;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.appToken.appId}")
|
||||||
|
private String appId;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.appToken.appSecuret}")
|
||||||
|
private String appSecuret;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.appToken.tenantid}")
|
||||||
|
private String tenantid;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.appToken.accountId}")
|
||||||
|
private String accountId;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.appToken.language}")
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.accessToken.user}")
|
||||||
|
private String user;
|
||||||
|
|
||||||
|
@Value("${ensign.kingdee.accessToken.usertype}")
|
||||||
|
private String usertype;
|
||||||
|
|
||||||
|
public String initBasePath() {
|
||||||
|
if ("test".equals(env)) {
|
||||||
|
if (isPublic) {
|
||||||
|
return testPublicEndPoint;
|
||||||
|
} else {
|
||||||
|
return testInnerEndPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("prod".equals(env)) {
|
||||||
|
if (isPublic) {
|
||||||
|
return prodPublicEndPoint;
|
||||||
|
} else {
|
||||||
|
return prodInnerEndPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public String initAccessToken() throws IOException, AllKingdeeException {
|
||||||
|
|
||||||
|
final String END_POINT = initBasePath() + "/ierp/api/getAppToken.do";
|
||||||
|
HttpClient client = new DefaultHttpClient();
|
||||||
|
|
||||||
|
HttpPost post = new HttpPost(END_POINT);
|
||||||
|
|
||||||
|
Map<String, String> body = new HashMap<>();
|
||||||
|
|
||||||
|
body.put("appId", appId);
|
||||||
|
body.put("appSecuret", appSecuret);
|
||||||
|
body.put("tenantid", tenantid);
|
||||||
|
body.put("accountId", accountId);
|
||||||
|
body.put("language", language);
|
||||||
|
|
||||||
|
HttpEntity reqEntity = new StringEntity(JSONUtil.toJsonStr(body), "utf-8");
|
||||||
|
|
||||||
|
post.setEntity(reqEntity);
|
||||||
|
post.setConfig(initRequestConfig());
|
||||||
|
HttpResponse response = client.execute(post);
|
||||||
|
if (response.getStatusLine().getStatusCode() == 200) {
|
||||||
|
|
||||||
|
HttpEntity resEntity = response.getEntity();
|
||||||
|
String responseData = EntityUtils.toString(resEntity, "utf-8");
|
||||||
|
JSONObject jsonObject = JSON.parseObject(responseData);
|
||||||
|
Boolean status = (Boolean) jsonObject.get("status");
|
||||||
|
String state = (String) jsonObject.get("state");
|
||||||
|
if (status && "success".equals(state)) {
|
||||||
|
JSONObject data = (JSONObject) jsonObject.get("data");
|
||||||
|
String appToken = (String) data.get("app_token");
|
||||||
|
if (appToken != null && !appToken.isEmpty()) {
|
||||||
|
return doGetAccessToken(appToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new AllKingdeeException("获取AppToken失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String doGetAccessToken(String appToken) throws IOException, AllKingdeeException {
|
||||||
|
|
||||||
|
HttpClient client = new DefaultHttpClient();
|
||||||
|
|
||||||
|
HttpPost post = new HttpPost(initBasePath() + "/ierp/api/login.do");
|
||||||
|
|
||||||
|
Map<String, String> body = new HashMap<>();
|
||||||
|
|
||||||
|
body.put("user", user);
|
||||||
|
body.put("apptoken", appToken);
|
||||||
|
body.put("tenantid", tenantid);
|
||||||
|
body.put("accountId", accountId);
|
||||||
|
body.put("language", language);
|
||||||
|
body.put("usertype", usertype);
|
||||||
|
|
||||||
|
HttpEntity reqEntity = new StringEntity(JSONUtil.toJsonStr(body), "utf-8");
|
||||||
|
|
||||||
|
post.setEntity(reqEntity);
|
||||||
|
post.setConfig(initRequestConfig());
|
||||||
|
HttpResponse response = client.execute(post);
|
||||||
|
|
||||||
|
if (response.getStatusLine().getStatusCode() == 200) {
|
||||||
|
|
||||||
|
HttpEntity resEntity = response.getEntity();
|
||||||
|
String responseData = EntityUtils.toString(resEntity, "utf-8");
|
||||||
|
JSONObject jsonObject = JSON.parseObject(responseData);
|
||||||
|
Boolean status = (Boolean) jsonObject.get("status");
|
||||||
|
String state = (String) jsonObject.get("state");
|
||||||
|
|
||||||
|
if (status && "success".equals(state)) {
|
||||||
|
JSONObject data = (JSONObject) jsonObject.get("data");
|
||||||
|
String accessToken = (String) data.get("access_token");
|
||||||
|
if (accessToken != null && !accessToken.isEmpty()) {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new AllKingdeeException("获取AccessToken失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
private RequestConfig initRequestConfig() {
|
||||||
|
return RequestConfig.custom()
|
||||||
|
.setConnectTimeout(5000)//一、连接超时:connectionTimeout-->指的是连接一个url的连接等待时间
|
||||||
|
.setSocketTimeout(5000)// 二、读取数据超时:SocketTimeout-->指的是连接上一个url,获取response的返回等待时间
|
||||||
|
.setConnectionRequestTimeout(5000)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -26,12 +26,15 @@ import java.nio.file.*;
|
|||||||
@Service
|
@Service
|
||||||
public class FileService {
|
public class FileService {
|
||||||
|
|
||||||
|
|
||||||
@Value("${collabora.file-storage-path}")
|
@Value("${collabora.file-storage-path}")
|
||||||
private String BASE_DIR;
|
private String BASE_DIR;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private KingdeeService kingdeeService;
|
||||||
|
|
||||||
public WopiFile getFileInfo(String fileId) {
|
public WopiFile getFileInfo(String fileId) {
|
||||||
Path filePath = Paths.get(BASE_DIR, fileId);
|
|
||||||
|
Path filePath = Paths.get(kingdeeService.requestFile(fileId));
|
||||||
|
|
||||||
File targetFile = filePath.toFile();
|
File targetFile = filePath.toFile();
|
||||||
|
|
||||||
@ -60,23 +63,18 @@ public class FileService {
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Resource loadFileAsResource(String fileId) {
|
public File loadFileAsResource(String fileId) {
|
||||||
try {
|
String requestFile = kingdeeService.requestFile(fileId);
|
||||||
Path resolvedPath = validateFilePath(fileId);
|
Path resolvedPath = new File(requestFile).toPath();
|
||||||
|
|
||||||
FileSystemResource resource = new FileSystemResource(resolvedPath);
|
return resolvedPath.toFile();
|
||||||
|
|
||||||
if (resource.exists() && resource.isReadable() && Files.isRegularFile(resolvedPath)) {
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch (InvalidPathException | SecurityException e) {
|
|
||||||
throw new RuntimeException("非法文件访问: " + fileId, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean saveFile(String fileId, InputStream content) {
|
public boolean saveFile(String fileId, InputStream content) {
|
||||||
Path targetPath = validateFilePath(fileId);
|
|
||||||
|
String requestFile = kingdeeService.requestFile(fileId);
|
||||||
|
|
||||||
|
Path targetPath = new File(requestFile).toPath();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Path tempFile = Files.createTempFile(targetPath.getParent(), "wopi_", ".tmp");
|
Path tempFile = Files.createTempFile(targetPath.getParent(), "wopi_", ".tmp");
|
||||||
@ -90,43 +88,9 @@ public class FileService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Files.move(tempFile, targetPath, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
|
Files.move(tempFile, targetPath, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
setFilePermissions(targetPath);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("文件保存失败: " + targetPath, e);
|
throw new RuntimeException("文件保存失败: " + targetPath, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path validateFilePath(String fileId) {
|
|
||||||
if (fileId.contains("..") || fileId.contains(":") || fileId.contains("\\\\")) {
|
|
||||||
throw new SecurityException("非法文件名: " + fileId);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path basePath = Paths.get(BASE_DIR).normalize().toAbsolutePath();
|
|
||||||
Path resolvedPath = basePath.resolve(fileId).normalize();
|
|
||||||
|
|
||||||
if (!resolvedPath.startsWith(basePath)) {
|
|
||||||
throw new SecurityException("路径越界访问: " + fileId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvedPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setFilePermissions(Path path) throws IOException {
|
|
||||||
if (!System.getProperty("os.name").toLowerCase().contains("win")) return;
|
|
||||||
|
|
||||||
String aclCommand = String.format(
|
|
||||||
"icacls \"%s\" /grant:r \"%s\":(F) /inheritance:r",
|
|
||||||
path.toString(),
|
|
||||||
System.getProperty("user.name")
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Runtime.getRuntime().exec(aclCommand).waitFor();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
package vin.vio.collaboraonline.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.client.ClientHttpRequest;
|
||||||
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import vin.vio.collaboraonline.exception.AllKingdeeException;
|
||||||
|
import vin.vio.collaboraonline.kingdee.AuthService;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static cn.hutool.http.HttpUtil.downloadFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @Date: 2025/2/21 16:40
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class KingdeeService {
|
||||||
|
|
||||||
|
@Value("${collabora.file-storage-path}")
|
||||||
|
private String BASE_DIR;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthService authService;
|
||||||
|
|
||||||
|
public String requestFile(String attPkId) {
|
||||||
|
try {
|
||||||
|
String accessToken = authService.initAccessToken();
|
||||||
|
URI newUri = new URI(authService.initBasePath() + "/ierp/kapi/v2/yem/yem_receipt/AttachmentsQueryAPI/Query");
|
||||||
|
|
||||||
|
ClientHttpRequest delegate = new SimpleClientHttpRequestFactory().createRequest(newUri, HttpMethod.POST);
|
||||||
|
delegate.getHeaders().add("access_token", accessToken);
|
||||||
|
delegate.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
||||||
|
Map<String, String> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("formId", "yem_testbill");
|
||||||
|
requestBody.put("pkId", attPkId);
|
||||||
|
requestBody.put("attachKey", "attachmentpanel");
|
||||||
|
String jsonBody = JSON.toJSONString(requestBody);
|
||||||
|
// 设置请求体
|
||||||
|
try (OutputStream os = delegate.getBody()) {
|
||||||
|
os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
ClientHttpResponse response = delegate.execute();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getBody()));
|
||||||
|
StringBuilder responseBody = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
responseBody.append(line);
|
||||||
|
}
|
||||||
|
String savePath = "";
|
||||||
|
JSONObject result = JSON.parseObject(responseBody.toString());
|
||||||
|
if (result.containsKey("status") && result.getBooleanValue("status", false)) {
|
||||||
|
JSONArray data = result.getJSONArray("data");
|
||||||
|
if (data != null && !data.isEmpty()) {
|
||||||
|
JSONObject data0 = data.getJSONObject(0);
|
||||||
|
String url = data0.getString("url");
|
||||||
|
String name = data0.getString("name");
|
||||||
|
savePath = BASE_DIR + "/" + name;
|
||||||
|
downloadFile(url, savePath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new AllKingdeeException(line);
|
||||||
|
}
|
||||||
|
return savePath;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,4 +8,24 @@ spring:
|
|||||||
|
|
||||||
# http://47.99.175.155:59980/browser/dist/cool.html?WOPISrc=http://47.99.175.155:59981/wopi/files/test.docx&lang=zh-cn
|
# http://47.99.175.155:59980/browser/dist/cool.html?WOPISrc=http://47.99.175.155:59981/wopi/files/test.docx&lang=zh-cn
|
||||||
|
|
||||||
# http://<collabora容器IP>:<端口>/browser/dist/cool.html?WOPISrc=http://<本机IP>:<服务端口>/wopi/files/<文件名>&lang=zh-cn
|
# http://<collabora容器IP>:<端口>/browser/dist/cool.html?WOPISrc=http://<本机IP>:<服务端口>/wopi/files/<文件名>&lang=zh-cn
|
||||||
|
|
||||||
|
|
||||||
|
# http://192.168.3.211:9980/browser/dist/cool.html?WOPISrc=http://192.168.3.104:8080/wopi/files/2087131858671270912&lang=zh-cn
|
||||||
|
ensign:
|
||||||
|
kingdee:
|
||||||
|
env: test
|
||||||
|
test-public-end-point: 'http://122.4.221.133:8022'
|
||||||
|
test-inner-end-point: 'http://10.64.112.152:8022'
|
||||||
|
prod-public-end-point: 'http://122.4.221.130:8022'
|
||||||
|
prod-inner-end-point: 'http://10.64.111.134:8022'
|
||||||
|
is-public: true
|
||||||
|
appToken:
|
||||||
|
appId: 'CRM'
|
||||||
|
appSecuret: 'yx.CRM.tksecurit@240924'
|
||||||
|
tenantid: 'yxzg-topview-dev'
|
||||||
|
accountId: '1878420900609526784'
|
||||||
|
language: 'zh_CN'
|
||||||
|
accessToken:
|
||||||
|
user: 'COSMIC'
|
||||||
|
usertype: 'UserName'
|
Loading…
Reference in New Issue
Block a user