提交 d8641917 authored 作者: JaxBBLL's avatar JaxBBLL

fix

上级 6909d900
<template> <template>
<view class="synchronous-dialog"> <view class="synchronous-dialog">
<view class="synchronous-content"> <view class="synchronous-content">
<view class="row-item"> <view class="row-item">
<text class="title">待打包数据</text> <text class="title">待打包数据</text>
</view> </view>
<view class="row-item count-num"> <view class="row-item count-num">
<text class="num">{{ list.length }}</text> <text class="num">{{ list.length }}</text>
<text></text> <text></text>
</view> </view>
<view class="operating-instructions"> <view class="operating-instructions">
<view class="title">操作说明:</view> <view class="title">操作说明:</view>
<view class="instructions-item"> <view class="instructions-item">
1、在PAD端,点击“数据打包”,做好同步准备。 1、在PAD端,点击“数据打包”,做好同步准备。
</view> </view>
<view class="instructions-item"> <view class="instructions-item">
2、完成打包后,将PAD直联PC机,等待PC机自动导入需同步记录。 2、完成打包后,将PAD直联PC机,等待PC机自动导入需同步记录。
</view> </view>
<view class="instructions-item"> <view class="instructions-item">
3、PC端自动导入完成后,请点击“同步数据”,同步成功后,列表自动刷新展示同步数据;且PAD同步的数据不支持修改。 3、PC端自动导入完成后,请点击“同步数据”,同步成功后,列表自动刷新展示同步数据;且PAD同步的数据不支持修改。
</view> </view>
</view> </view>
<view class="row-item bottom-row"> <view class="row-item bottom-row">
<button class="button" :loading="loading" @click="clickHandle"> <button class="button" :loading="loading" @click="clickHandle">
数据打包 数据打包
</button> </button>
</view> </view>
<!-- 关闭按钮 --> <!-- 关闭按钮 -->
<div class="close-button"> <div class="close-button">
<text class="iconfont icon-shibai1" @click="close"></text> <text class="iconfont icon-shibai1" @click="close"></text>
</div> </div>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import { import {
SYNCHRONIZE_DATA_PAD, SYNCHRONIZE_DATA_PAD,
checkAndCreateDirectory, checkAndCreateDirectory,
createFileWithPlusIO, createFileWithPlusIO,
setSm2, setSm2,
USER_FILE_NAME, USER_FILE_NAME,
getUserList, getUserList,
zipCompress zipCompress,
} from "@/utils/systemCofig"; } from "@/utils/systemCofig";
import { import { findPhotosUrls } from "@/utils/index.js";
findPhotosUrls import { copySelectedFiles } from "@/utils/plus.js";
} from "@/utils/index.js";
import { import {
copySelectedFiles writeInspectionData,
} from "@/utils/plus.js"; copyDirectory,
deleteAllFilesInDirectory,
import { addLog,
writeInspectionData, getLogContent,
copyDirectory, LOG_TYPE_ENUM,
deleteAllFilesInDirectory, } from "@/utils/IoReadingAndWriting.js";
addLog, import moment from "moment";
getLogContent, import { getAllInspections } from "@/request/index.js";
LOG_TYPE_ENUM, import { Base64 } from "js-base64";
} from "@/utils/IoReadingAndWriting.js"; import inspectApi from "@/api/inspect";
import moment from "moment"; import inspect from "@/api/inspect";
import { export default {
getAllInspections props: {
} from "@/request/index.js"; list: {
import { type: Array,
Base64 default: () => {},
} from "js-base64"; },
import inspectApi from "@/api/inspect"; },
import inspect from "@/api/inspect"; components: {},
export default { data() {
props: { return {
list: { loading: false,
type: Array, notSynchronizationList: [], // 未同步数据
default: () => {}, allList: [], // 所有数据
}, };
}, },
components: {}, computed: {
data() { userInfo() {
return { return this.$store.state.now_user;
loading: false, },
notSynchronizationList: [], // 未同步数据 },
allList: [], // 所有数据
}; watch: {
}, list(newVal) {
computed: { console.log("newVal", newVal);
userInfo() { this.init();
return this.$store.state.now_user; },
}, },
}, // async mounted() {
// const temp = [];
watch: { // this.list.forEach((item) => {
list(newVal) { // temp.push(...(item.list || []));
console.log("newVal", newVal); // });
this.init(); // console.log("this.list", this.list);
}, // console.log("temp", temp);
}, // this.notSynchronizationList = temp.filter(
// async mounted() { // (item) => item.synchronization == 0 && item.isSign === true
// const temp = []; // );
// this.list.forEach((item) => {
// temp.push(...(item.list || [])); // getAllInspections().then((res) => {
// }); // this.allList = res;
// console.log("this.list", this.list); // });
// console.log("temp", temp); // },
// this.notSynchronizationList = temp.filter( methods: {
// (item) => item.synchronization == 0 && item.isSign === true init() {
// ); const temp = [];
this.notSynchronizationList = this.list;
// getAllInspections().then((res) => {
// this.allList = res; getAllInspections().then((res) => {
// }); this.allList = res;
// }, });
methods: { },
init() { close() {
const temp = []; this.$emit("close");
this.notSynchronizationList = this.list; },
getAllInspections().then((res) => { /**
this.allList = res; * 1.生成两个文件. 机房文件 和 井道文件
}); * 2. 更新巡检数据状态 synchronization 置为 1
}, * 3. 写入数据
close() { * 读取上一次打包的文件, 复制到 [ history ] 文件夹中
this.$emit("close"); */
}, async clickHandle() {
if (this.loading) return;
/** const directoryPath = `${SYNCHRONIZE_DATA_PAD}/发送数据`;
* 1.生成两个文件. 机房文件 和 井道文件 const targetDirectoryPath = `${SYNCHRONIZE_DATA_PAD}/history/${new Date().getTime()}`;
* 2. 更新巡检数据状态 synchronization 置为 1
* 3. 写入数据 // checkAndCreateDirectory(directoryPath).then(() => {
* 读取上一次打包的文件, 复制到 [ history ] 文件夹中 copyDirectory(directoryPath, targetDirectoryPath)
*/ .then(() => {
async clickHandle() { return deleteAllFilesInDirectory(directoryPath);
if (this.loading) return; })
const directoryPath = `${SYNCHRONIZE_DATA_PAD}/发送数据`; .then(() => {
const targetDirectoryPath = `${SYNCHRONIZE_DATA_PAD}/history/${new Date().getTime()}`; this.coverData();
})
// checkAndCreateDirectory(directoryPath).then(() => { .catch((error) => {
copyDirectory(directoryPath, targetDirectoryPath) uni.showToast({
.then(() => { title: error,
return deleteAllFilesInDirectory(directoryPath); icon: "none",
}) duration: 1000,
.then(() => { });
this.coverData(); });
}) // });
.catch((error) => { },
uni.showToast({ copyPhotos() {
title: error, this.list.forEach((e) => {
icon: "none", if (typeof e.inspectionData === "string") {
duration: 1000, e.inspectionData = JSON.parse(e.inspectionData) || "{}";
}); }
}); });
// }); const urls = findPhotosUrls(this.list).map((url) => url.split("/").pop());
}, console.log("urls", urls);
copyPhotos() { return copySelectedFiles(
this.list.forEach(e => { "_documents/data/photos",
e.inspectionData = JSON.parse(e.inspectionData) || '{}' `${SYNCHRONIZE_DATA_PAD}/发送数据`,
}) urls
const urls = findPhotosUrls(this.list).map((url) => url.split("/").pop()); );
console.log("urls", urls); },
return copySelectedFiles( // 处理数据
"_documents/data/photos", coverData() {
`${SYNCHRONIZE_DATA_PAD}/发送数据`, const userName = this.$store.state.now_user.user;
urls const notSynchronizationList = this.notSynchronizationList;
); const allList = this.allList;
}, console.log("窗口allList", allList);
// 处理数据 console.log(
coverData() { "窗口this.notSynchronizationList",
const userName = this.$store.state.now_user.user; this.notSynchronizationList
const notSynchronizationList = this.notSynchronizationList; );
const allList = this.allList;
console.log("窗口allList", allList); let timeStr = moment().format("yyyy_MM_DD_hh_mm_ss");
console.log(
"窗口this.notSynchronizationList", const JFXJ_DATA = notSynchronizationList
this.notSynchronizationList .filter((item) => item.inspectionType == 1)
); .map((item) => {
return item;
let timeStr = moment().format("yyyy_MM_DD_hh_mm_ss"); }); // 机房数据类型是 1
const JFXJ_DATA = notSynchronizationList const JDXJ_DATA = notSynchronizationList
.filter((item) => item.inspectionType == 1) .filter((item) => item.inspectionType == 2)
.map((item) => { .map((item) => {
return item; return item;
}); // 机房数据类型是 1 }); // 井道数据类型是 2
console.log(5151, JFXJ_DATA, JDXJ_DATA);
const JDXJ_DATA = notSynchronizationList
.filter((item) => item.inspectionType == 2) this.loading = true;
.map((item) => { const tmepList = [];
return item;
}); // 井道数据类型是 2 if (JFXJ_DATA.length) {
console.log(5151, JFXJ_DATA, JDXJ_DATA); let JFXJ_DATA_FILE_NAME = `${userName}_JFXJ_${timeStr}.txt`;
tmepList.push(this.packedData(JFXJ_DATA, JFXJ_DATA_FILE_NAME));
this.loading = true; }
const tmepList = [];
if (JDXJ_DATA.length) {
if (JFXJ_DATA.length) { let JDXJ_DATA_FILE_NAME = `${userName}_JDXJ_${timeStr}.txt`;
let JFXJ_DATA_FILE_NAME = `${userName}_JFXJ_${timeStr}.txt`; tmepList.push(this.packedData(JDXJ_DATA, JDXJ_DATA_FILE_NAME));
tmepList.push(this.packedData(JFXJ_DATA, JFXJ_DATA_FILE_NAME)); }
}
console.log("同步窗口");
JDXJ_DATA.forEach((item, index) => { console.log("同步窗口", tmepList);
let JDXJ_DATA_FILE_NAME = `${userName}_JDXJ_${timeStr}_${index}.txt`; Promise.all(tmepList)
tmepList.push(this.packedData(item, JDXJ_DATA_FILE_NAME)); .then(() => {
}); // 更新巡检数据状态
const synchronizationUids = notSynchronizationList.map((item) => {
console.log("同步窗口"); item.synchronization = 1;
console.log("同步窗口", tmepList); return item.uid;
Promise.all(tmepList) });
.then(() => {
// 更新巡检数据状态 const userData = {};
const synchronizationUids = notSynchronizationList.map((item) => {
item.synchronization = 1; allList.forEach((item) => {
return item.uid; if (synchronizationUids.includes(item.uid)) {
}); item.synchronization = 1;
}
const userData = {}; if (userData[item.createByName]) {
userData[item.createByName].push(item);
allList.forEach((item) => { } else {
if (synchronizationUids.includes(item.uid)) { userData[item.createByName] = [item];
item.synchronization = 1; }
} });
if (userData[item.createByName]) { this.$store.commit("SET_ALL_DATA", allList);
userData[item.createByName].push(item);
} else { const keys = Object.keys(userData);
userData[item.createByName] = [item]; const promiseArr = keys.map((key) => {
} const val = userData[key];
}); return writeInspectionData(val, key);
this.$store.commit("SET_ALL_DATA", allList); });
const keys = Object.keys(userData); Promise.all(promiseArr)
const promiseArr = keys.map((key) => { .then(async () => {
const val = userData[key]; setTimeout(async () => {
return writeInspectionData(val, key); uni.showToast({
}); title: "打包成功",
icon: "none",
Promise.all(promiseArr) duration: 2000,
.then(async () => { });
setTimeout(async () => { let ids = this.list.map((e) => e.id);
uni.showToast({ // 复制照片
title: "打包成功", await this.copyPhotos();
icon: "none", zipCompress(
duration: 2000, `${SYNCHRONIZE_DATA_PAD}/发送数据`,
}); `${SYNCHRONIZE_DATA_PAD}/fssj/${userName}_JFXJ_${timeStr}.zip`
let ids = this.list.map((e) => e.id); );
// 复制照片 // zip
await this.copyPhotos(); await inspectApi.updateSyncData(ids);
zipCompress(`${SYNCHRONIZE_DATA_PAD}/发送数据`, this.close();
`${SYNCHRONIZE_DATA_PAD}/fssj/${userName}_JFXJ_${timeStr}.zip` this.loading = false;
);
// zip // 生成日志
await inspectApi.updateSyncData(ids); const logContent = getLogContent(
this.close(); LOG_TYPE_ENUM.sys,
this.loading = false; "",
"同步模块"
// 生成日志 );
const logContent = getLogContent( const log_list = this.$store.state.log_list;
LOG_TYPE_ENUM.sys, log_list.push(logContent);
"", this.$store.commit("SET_LOG_LIST", log_list);
"同步模块" addLog(log_list).then((res) => {});
);
const log_list = this.$store.state.log_list; // 更新同步时间
log_list.push(logContent); this.updateSysTime();
this.$store.commit("SET_LOG_LIST", log_list); }, 2 * 1000);
addLog(log_list).then((res) => {}); })
.catch((error) => {
// 更新同步时间 this.loading = false;
this.updateSysTime();
uni.showToast({
title: error,
}, 2 * 1000); icon: "none",
}) duration: 2000,
.catch((error) => { });
this.loading = false; });
})
uni.showToast({ .catch(() => {
title: error, setTimeout(() => {
icon: "none", uni.showToast({
duration: 2000, title: "打包失败",
}); icon: "none",
}); duration: 2000,
}) });
.catch(() => { this.loading = false;
setTimeout(() => { }, 2 * 1000);
uni.showToast({ });
title: "打包失败", },
icon: "none",
duration: 2000, // 使用示例
}); // 打包文件
this.loading = false; packedData(content, fileName) {
}, 2 * 1000); // const fileContent = setSm2(content);
}); const fileContent = Base64.encode(JSON.stringify(content));
},
console.log("packedData", fileContent);
return createFileWithPlusIO(
// 使用示例 `${SYNCHRONIZE_DATA_PAD}/发送数据`,
// 打包文件 fileName,
packedData(content, fileName) { fileContent
// const fileContent = setSm2(content); );
const fileContent = Base64.encode(JSON.stringify(content)); },
console.log("packedData", fileContent); // 更新最近一次同步时间
return createFileWithPlusIO( updateSysTime() {
`${SYNCHRONIZE_DATA_PAD}/发送数据`, getUserList().then((personList) => {
fileName, const now_user = this.$store.state.now_user;
fileContent const key = personList.findIndex(
); (item) => item.userId == now_user.userId
}, );
// 更新用户同步时间
// 更新最近一次同步时间 const userInfo = personList[key];
updateSysTime() { const LastSynchronizationTime = moment().format("yyyy-MM-DD HH:mm");
getUserList().then((personList) => { personList[key].LastSynchronizationTime = LastSynchronizationTime;
const now_user = this.$store.state.now_user; userInfo.LastSynchronizationTime = LastSynchronizationTime;
const key = personList.findIndex(
(item) => item.userId == now_user.userId this.$store.commit("SET_USER", userInfo);
); uni.setStorageSync("last_time", userInfo.LastSynchronizationTime || "");
// 更新用户同步时间
const userInfo = personList[key]; // 更新用户数据
const LastSynchronizationTime = moment().format("yyyy-MM-DD HH:mm"); const fileContent = JSON.stringify(
personList[key].LastSynchronizationTime = LastSynchronizationTime; Base64.encode(JSON.stringify(personList))
userInfo.LastSynchronizationTime = LastSynchronizationTime; );
uni.setStorage({
this.$store.commit("SET_USER", userInfo); key: "user_data",
uni.setStorageSync("last_time", userInfo.LastSynchronizationTime || ""); data: JSON.stringify(personList),
fail: (error) => {
// 更新用户数据 console.log("APP.vue 存储数据失败", error);
const fileContent = JSON.stringify( },
Base64.encode(JSON.stringify(personList)) });
); createFileWithPlusIO(SYNCHRONIZE_DATA_PAD, USER_FILE_NAME, fileContent)
uni.setStorage({ .then(() => {
key: "user_data", console.log("---用户数据更新成功");
data: JSON.stringify(personList), })
fail: (error) => { .catch((error) => {
console.log("APP.vue 存储数据失败", error); console.log("---用户数据更新失败", error);
}, });
}); });
createFileWithPlusIO(SYNCHRONIZE_DATA_PAD, USER_FILE_NAME, fileContent) },
.then(() => { },
console.log("---用户数据更新成功"); };
})
.catch((error) => {
console.log("---用户数据更新失败", error);
});
});
},
},
};
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.synchronous-dialog { .synchronous-dialog {
position: fixed; position: fixed;
z-index: 999; z-index: 999;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
.synchronous-content { .synchronous-content {
padding: 3% 20px 32px 24px; padding: 3% 20px 32px 24px;
width: 400px; width: 400px;
height: 60%; height: 60%;
box-sizing: border-box; box-sizing: border-box;
background-image: linear-gradient(-6deg, background-image: linear-gradient(
#f9ffe7 0%, -6deg,
#ffffff 12%, #f9ffe7 0%,
#fcfeff 73%, #ffffff 12%,
#ccf1ff 100%); #fcfeff 73%,
border: 0.4px solid rgba(224, 224, 224, 1); #ccf1ff 100%
border-radius: 12px; );
position: relative; border: 0.4px solid rgba(224, 224, 224, 1);
border-radius: 12px;
.row-item { position: relative;
display: flex;
align-items: center; .row-item {
justify-content: center; display: flex;
} align-items: center;
justify-content: center;
.title { }
font-family: PingFangSC-Medium;
font-size: 18px; .title {
color: #000000; font-family: PingFangSC-Medium;
text-align: center; font-size: 18px;
line-height: 26px; color: #000000;
font-weight: 500; text-align: center;
} line-height: 26px;
font-weight: 500;
.count-num { }
margin: 5% 0 5% 0;
align-items: flex-end; .count-num {
margin: 5% 0 5% 0;
.num { align-items: flex-end;
display: inline-block;
font-family: AlibabaPuHuiTi_2_65_Medium; .num {
font-size: 50px; display: inline-block;
color: #3774f6; font-family: AlibabaPuHuiTi_2_65_Medium;
line-height: 44px; font-size: 50px;
font-weight: 500; color: #3774f6;
} line-height: 44px;
} font-weight: 500;
}
.operating-instructions { }
margin-bottom: 8%;
.operating-instructions {
.title { margin-bottom: 8%;
font-size: 13px;
color: #4a4a4a; .title {
line-height: 24px; font-size: 13px;
font-weight: 600; color: #4a4a4a;
text-align: left; line-height: 24px;
} font-weight: 600;
text-align: left;
.instructions-item { }
font-size: 12px;
color: #7c7c7c; .instructions-item {
line-height: 22px; font-size: 12px;
font-weight: 400; color: #7c7c7c;
} line-height: 22px;
} font-weight: 400;
}
// 打包按钮 }
.bottom-row {
position: absolute; // 打包按钮
bottom: 24px; .bottom-row {
left: 50%; position: absolute;
transform: translateX(-50%); bottom: 24px;
left: 50%;
.button { transform: translateX(-50%);
display: flex;
align-items: center; .button {
justify-content: center; display: flex;
background-image: linear-gradient(180deg, #3773f6 0%, #2c57f6 99%); align-items: center;
box-shadow: 0px 10px 24px 0px rgba(51, 104, 246, 0.24); justify-content: center;
border-radius: 27px; background-image: linear-gradient(180deg, #3773f6 0%, #2c57f6 99%);
width: 160px; box-shadow: 0px 10px 24px 0px rgba(51, 104, 246, 0.24);
height: 40px; border-radius: 27px;
color: #fff; width: 160px;
} height: 40px;
} color: #fff;
}
// 关闭按钮 }
.close-button {
position: absolute; // 关闭按钮
bottom: -40px; .close-button {
left: 50%; position: absolute;
transform: translateX(-50%); bottom: -40px;
left: 50%;
.iconfont { transform: translateX(-50%);
font-size: 24px;
} .iconfont {
} font-size: 24px;
} }
} }
</style> }
\ No newline at end of file }
</style>
...@@ -113,18 +113,16 @@ export default { ...@@ -113,18 +113,16 @@ export default {
* 读取上一次打包的文件, 复制到 [ history ] 文件夹中 * 读取上一次打包的文件, 复制到 [ history ] 文件夹中
*/ */
clickHandle() { clickHandle() {
if(this.loading) return; if (this.loading) return;
const directoryPath = `${SYNCHRONIZE_DATA_PAD}/发送数据`; const directoryPath = `${SYNCHRONIZE_DATA_PAD}/发送数据`;
const targetDirectoryPath = `${SYNCHRONIZE_DATA_PAD}/history`; const targetDirectoryPath = `${SYNCHRONIZE_DATA_PAD}/history`;
checkAndCreateDirectory(directoryPath).then(() => { checkAndCreateDirectory(directoryPath).then(() => {
copyDirectory(directoryPath, targetDirectoryPath) copyDirectory(directoryPath, targetDirectoryPath)
.then(() => { .then(() => {
return deleteAllFilesInDirectory(directoryPath); return deleteAllFilesInDirectory(directoryPath);
}) })
.then(() => { .then(() => {
this.coverData(); this.coverData();
}) })
.catch((error) => { .catch((error) => {
...@@ -142,7 +140,6 @@ export default { ...@@ -142,7 +140,6 @@ export default {
const notSynchronizationList = this.notSynchronizationList; const notSynchronizationList = this.notSynchronizationList;
const allList = this.allList; const allList = this.allList;
let timeStr = moment().format("yyyy_MM_DD_hh_mm_ss"); let timeStr = moment().format("yyyy_MM_DD_hh_mm_ss");
const JFXJ_DATA = notSynchronizationList const JFXJ_DATA = notSynchronizationList
...@@ -160,19 +157,17 @@ export default { ...@@ -160,19 +157,17 @@ export default {
return item[item.inspectionCode]; return item[item.inspectionCode];
}); // 井道数据类型是 2 }); // 井道数据类型是 2
this.loading = true; this.loading = true;
const tmepList = []; const tmepList = [];
if (JFXJ_DATA.length) { if (JFXJ_DATA.length) {
let JFXJ_DATA_FILE_NAME = `${userName}_JFXJ_${timeStr}.txt`; let JFXJ_DATA_FILE_NAME = `${userName}_JFXJ_${timeStr}.txt`;
tmepList.push(this.packedData(JFXJ_DATA, JFXJ_DATA_FILE_NAME)); tmepList.push(this.packedData(JDXJ_DATA, JFXJ_DATA_FILE_NAME));
}
if (JDXJ_DATA.length) {
let JDXJ_DATA_FILE_NAME = `${userName}_JDXJ_${timeStr}.txt`;
tmepList.push(this.packedData(JDXJ_DATA, JDXJ_DATA_FILE_NAME));
} }
JDXJ_DATA.forEach((item, index) => {
let JDXJ_DATA_FILE_NAME = `${userName}_JDXJ_${timeStr}_${index}.txt`;
tmepList.push(this.packedData(item, JDXJ_DATA_FILE_NAME));
});
Promise.all(tmepList) Promise.all(tmepList)
.then(() => { .then(() => {
...@@ -223,8 +218,7 @@ export default { ...@@ -223,8 +218,7 @@ export default {
const log_list = this.$store.state.log_list; const log_list = this.$store.state.log_list;
log_list.push(logContent); log_list.push(logContent);
this.$store.commit("SET_LOG_LIST", log_list); this.$store.commit("SET_LOG_LIST", log_list);
addLog(log_list).then((res) => { addLog(log_list).then((res) => {});
});
// 更新同步时间 // 更新同步时间
this.updateSysTime(); this.updateSysTime();
...@@ -290,12 +284,13 @@ export default { ...@@ -290,12 +284,13 @@ export default {
console.log("APP.vue 存储数据失败", error); console.log("APP.vue 存储数据失败", error);
}, },
}); });
createFileWithPlusIO(SYNCHRONIZE_DATA_PAD, USER_FILE_NAME, fileContent).then(() => { createFileWithPlusIO(SYNCHRONIZE_DATA_PAD, USER_FILE_NAME, fileContent)
console.log("---用户数据更新成功") .then(() => {
}).catch(error => { console.log("---用户数据更新成功");
console.log("---用户数据更新失败", error) })
.catch((error) => {
}) console.log("---用户数据更新失败", error);
});
}); });
}, },
}, },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论