3
1

11 کامیت‌ها 59330ac8dd ... d32a35af55

نویسنده SHA1 پیام تاریخ
  fanghuisheng d32a35af55 修复二维码巡检点位详情BUG问题/新增默认示意图 2 هفته پیش
  gez 1834331eef Merge branch 'wangtao' of uskycloud/usky-web-mobile into master 2 هفته پیش
  wangtao 0cb2514a80 修复加密文件jsencrypt引用错误问题 3 هفته پیش
  gez f1885c700c Merge branch 'wangtao' of uskycloud/usky-web-mobile into master 3 هفته پیش
  wangtao 43cbc2c3d0 首页租户列表过多无法滑动问题修复 3 هفته پیش
  wangtao 1f23b0715d 添加觉大版本内容校验 1 ماه پیش
  王涛 7b17654c98 Merge branch 'wangtao' of uskycloud/usky-web-mobile into master 1 ماه پیش
  wangtao f9801302f3 服务评价调整 1 ماه پیش
  王涛 930cf7e1f9 Merge branch 'wangtao' of uskycloud/usky-web-mobile into master 1 ماه پیش
  wangtao 197fa747a9 白名单调整评分页面路径 1 ماه پیش
  wangtao 663c16aafe 觉大版本调整 1 ماه پیش

+ 0 - 2
README.md

@@ -7,5 +7,3 @@
 ## node>18.1.0||16.17.1
  
 ##### 提交时执行 npm run update:setting "zhiHuiYun",防止每次文件变更
-
-

+ 2 - 2
src/pages.json

@@ -771,14 +771,14 @@
                 {
                     "path": "repairReport/index",
                     "style": {
-                        "navigationBarTitleText": "报修申请",
+                        "navigationBarTitleText": "",
                         "enablePullDownRefresh": false
                     }
                 },
                 {
                     "path": "repairReport/record",
                     "style": {
-                        "navigationBarTitleText": "报修历史",
+                        "navigationBarTitleText": "",
                         "enablePullDownRefresh": false
                     }
                 }

+ 35 - 4
src/pages/business/common/projectMange/list/index.vue

@@ -99,8 +99,11 @@
                 proxy.$common.mapping("label", "value", base.visibleRange, project_displayType)
               }}</span>
             </view>
-            <view class="content-area-row_wrap-view" style="display: block">
-              成员:<span >{{ proxy.$common.mapping("nickName", "userId", base.projectMember, userDate) }} </span>
+            <view class="content-area-row_wrap-view" style="display: block;position: relative;">
+              成员:<span :class='{ "omit": base.omit &&base.omit[0] }'>
+                      {{ base.projectMemberName }} 
+                    </span> 
+                    <uni-icons :type="base.omit[0] ? 'down' : 'up'" size="20" style="color:rgba(102, 102, 102,1)" class="omitIcon" @click="omitIconClick(base)" v-if="base.omit[0] || base.omit[1]>30"></uni-icons>
             </view>
           </view>
         </view>
@@ -276,7 +279,6 @@ function handleAction(value, event, index, ind) {
 function selectAction(e) {
   state.projectType = e.value[0].value;
   state.projectTypeName = e.value[0].label;
-  console.log(state.projectType, state.projectTypeName,e)
   state.actionShow = false;
 }
 
@@ -286,8 +288,8 @@ function selectAction(e) {
 function init() {
   dUserList().then((res) => {
     state.userDate = res.data;
+    selectListApi();
   });
-  selectListApi();
 }
 
 /**
@@ -301,6 +303,13 @@ function handleModal(type, content) {
   state.modal.content = content;
 }
 
+function omitIconClick(val){
+  for(let i=0;i<state.dataList.length;i++){
+    if(val.id == state.dataList[i].id){
+      state.dataList[i].omit[0] =!state.dataList[i].omit[0]
+    }
+  }
+}
 /** 确定按钮点击事件 */
 function handleSubmit(type, item) {
   if (type === "insert") {
@@ -366,6 +375,14 @@ function selectListApi() {
     })
     .then((requset) => {
       state.dataList = requset.data.records;
+      for(let i =0;i<state.dataList.length;i++){
+        state.dataList[i].projectMemberName = ""
+        state.dataList[i].omit = [false]
+        if(state.dataList[i].projectMember){
+          state.dataList[i].projectMemberName = proxy.$common.mapping("nickName", "userId", state.dataList[i].projectMember, state.userDate)
+          state.dataList[i].omit = [state.dataList[i].projectMemberName.length>30,state.dataList[i].projectMemberName.length]
+        }
+      }
       state.total = requset.data.total;
       state.loading = false;
     })
@@ -551,4 +568,18 @@ onLoad((options) => {});
   line-height: 20px !important;
   border-radius: 10px;
 }
+.omit{
+  width:85%;
+  display: inline-block;
+  vertical-align: middle;
+  overflow: hidden; 
+  white-space: nowrap; 
+  text-overflow: ellipsis;
+}
+.omitIcon{
+  position: absolute;
+  right:0;
+  bottom:0;
+  color:rgba(102, 102, 102,1)
+}
 </style>

+ 40 - 24
src/pages/business/common/projectMange/write/components/template1.vue

@@ -148,7 +148,7 @@
 
   <u-datetime-picker :show="timeShow" v-model="timeValue" mode="datetime" :closeOnClickOverlay="true" @cancel="timeShow = false" @confirm="timeConfirm"></u-datetime-picker>
 
-  <u-modal :show="modalShow" title="" :confirmText="'确定'" :cancelText="'取消'" :zoom="false" :showCancelButton="true" @confirm="modalConfirm" @cancel="modalShow = false">
+  <u-modal :show="modalShow" title="" :confirmText="'确定'" :cancelText="'取消'" :zoom="false" :showCancelButton="true" @confirm="modalConfirm" @cancel="modalShow = false" :picker-options="pickerOptions">
     <view class="slot-content" style="max-height: 45vh; overflow: scroll !important;">
       <view v-if="projectsList.length > 0" >
         <scroll-view scroll-y style="height: 100%; max-height: 300px;">
@@ -188,7 +188,7 @@
       </u-checkbox-group> -->
       </view>
 
-      <view v-else>请联系项目管理人员给您分配项目后重试!</view>
+      <view v-else>暂未添加项目,请点击确定前往“项目列表”,成为项目成员。</view>
     </view>
   </u-modal>
 </template>
@@ -207,6 +207,7 @@ import { systemStores } from "@/store/modules/index";
 /*----------------------------------公共方法引入-----------------------------------*/
 import { storageSystem } from "@/utils/storage"; // 公共方法引用
 import config from "@/config";
+import dayjs from "dayjs";
 /*----------------------------------公共变量-----------------------------------*/
 const { proxy } = getCurrentInstance();
 const systemStore = systemStores();
@@ -217,7 +218,6 @@ const props = defineProps({
   },
 });
 /*----------------------------------变量声明-----------------------------------*/
-
 const modal = reactive({
   timeShow: false,
   timeValue: Number(new Date()),
@@ -247,6 +247,9 @@ const reportFile1 = ref([]); //附件
 const { timeShow, timeValue, modalShow } = toRefs(modal);
 const { form, projectsCheck, projectsList, userList, userDate, saveTime } = toRefs(state);
 
+
+
+const disabledDate = (time) => time > Date.now();
 /**
  * @初始化
  */
@@ -258,8 +261,16 @@ function init() {
 
 /** 时间选择器确定按钮点击事件 */
 function timeConfirm(e) {
-  state.form.timingTime = proxy.$time.getFormatterDate(e.value);
-  modal.timeShow = false;
+  const currentTime = dayjs().unix() * 1000; //当前时间戳
+  const tomorrowZeroPoint = dayjs(dayjs().add(1, 'day').format('YYYY-MM-DD') + " 00:00:00").valueOf(); //第二日零点时间戳
+  if(e.value < tomorrowZeroPoint && e.value > currentTime){
+    state.form.timingTime = proxy.$time.getFormatterDate(e.value);
+    modal.timeShow = false;
+  }else if(e.value > tomorrowZeroPoint){
+    proxy.$modal.msg("请选择当天时间!");
+  }else if(e.value < currentTime){
+    proxy.$modal.msg("选择时间要大约当前时间!");
+  }
 }
 
 /** 开关按钮change事件 */
@@ -310,28 +321,33 @@ function realTimeSaving() {
 
 /** 弹窗确定 */
 function modalConfirm() {
-  var newWorkContents = JSON.parse(JSON.stringify(state.form.workContents));
-  state.form.workContents = [];
-
-  state.projectsCheck.forEach((e) => {
-    state.form.workContents.push({
-      projectId: e,
-      projectName: proxy.$common.mapping("projectName", "id", e, state.projectsList),
-      workTime: "",
-      workContent: "",
+  if(projectsList.value.length){
+    var newWorkContents = JSON.parse(JSON.stringify(state.form.workContents));
+    state.form.workContents = [];
+  
+    state.projectsCheck.forEach((e) => {
+      state.form.workContents.push({
+        projectId: e,
+        projectName: proxy.$common.mapping("projectName", "id", e, state.projectsList),
+        workTime: "",
+        workContent: "",
+      });
     });
-  });
-
-  newWorkContents.forEach((e) => {
-    state.form.workContents.forEach((f) => {
-      if (e.projectId == f.projectId) {
-        f.workTime = e.workTime;
-        f.workContent = e.workContent;
-      }
+  
+    newWorkContents.forEach((e) => {
+      state.form.workContents.forEach((f) => {
+        if (e.projectId == f.projectId) {
+          f.workTime = e.workTime;
+          f.workContent = e.workContent;
+        }
+      });
     });
-  });
+    modal.modalShow = false;
+  }else{
+    modal.modalShow = false;
+    proxy.$tab.redirectTo("/pages/business/common/projectMange/list/index"); 
+  }
 
-  modal.modalShow = false;
   // realTimeSaving();
 }
 

+ 19 - 9
src/pages/business/fireIot/repairReport/index.vue

@@ -14,7 +14,8 @@
       <view class="list-cell">
         <view class="menu-item font14">
           <view style="margin-right: auto; color: #666666"></view>
-          <view style="color: #149eff" @click="proxy.$tab.navigateTo(`/pages/business/fireIot/repairReport/record`)">报修历史</view>
+          <!-- <view style="color: #149eff" @click="proxy.$tab.navigateTo(`/pages/business/fireIot/repairReport/record`)" v-if="jd">历史记录</view> -->
+          <view style="color: #149eff" @click="proxy.$tab.navigateTo(`/pages/business/fireIot/repairReport/record`)" v-if="!jd">报修历史</view>
         </view>
 
         <u--form :model="form" ref="uForm" :rules="rules" labelWidth="80">
@@ -30,14 +31,14 @@
               <u-form-item label="项目地址" prop="projectAddress" :borderBottom="true" required>
                 <u-input v-model="form.projectAddress" placeholder="请填写项目地址" border="none" />
               </u-form-item>
-              <u-form-item label="报修人" prop="reflectName" :borderBottom="true" required>
-                <u-input v-model="form.reflectName" placeholder="请填写报修人" border="none" maxlength="10" />
+              <u-form-item :label="jd ? '填报人' : '报修人'" prop="reflectName" :borderBottom="true" required>
+                <u-input v-model="form.reflectName" :placeholder=" jd ? '请填写填报人' : '请填写报修人'" border="none" maxlength="10" />
               </u-form-item>
               <u-form-item label="手机号" prop="reflectPhone" :borderBottom="true" required>
                 <u-input v-model="form.reflectPhone" placeholder="请填写手机号" border="none" maxlength="11" />
               </u-form-item>
-              <u-form-item label="问题描述" prop="repairContent" :borderBottom="true" required>
-                <u--textarea v-model="form.repairContent" border="none" placeholder="请填写问题描述" maxlength="100" style="padding: 0"></u--textarea>
+              <u-form-item :label="jd ? '描述' : '问题描述'" prop="repairContent" :borderBottom="true" required>
+                <u--textarea v-model="form.repairContent" border="none" :placeholder="jd ? '请填写描述' : '请填写问题描述'" maxlength="100" style="padding: 0"></u--textarea>
               </u-form-item>
               <u-form-item label="上传图片" prop="repairPicture" :borderBottom="true">
                 <oa-upload :uploadCount="1" :uploadImage="form.repairPicture" @uploadSuccessChange="uploadSuccessChange" @uploadDeleteChange="uploadDeleteChange"></oa-upload>
@@ -79,12 +80,12 @@ import { ref, reactive, computed, getCurrentInstance, toRefs, inject } from "vue
 import { add, getAddHistoryInfo } from "@/api/business/fireIot/repairReport.js";
 /*----------------------------------组件引入-----------------------------------*/
 /*----------------------------------store引入-----------------------------------*/
-import { useStores, commonStores } from "@/store/modules/index";
 /*----------------------------------公共方法引入-----------------------------------*/
+import config from "@/config";
 /*----------------------------------公共变量-----------------------------------*/
 const { proxy } = getCurrentInstance();
-const commonStore = commonStores();
 /*----------------------------------变量声明-----------------------------------*/
+const jd = ref(config.baseUrl.indexOf("manager.juedatech.com") > -1) //觉大环境判断
 const uForm = ref(null);
 const state = reactive({
   form: {
@@ -99,12 +100,12 @@ const state = reactive({
   rules: {
     projectName: [{ required: true, message: "请填写项目名称", trigger: ["blur", "change"] }],
     projectName: [{ required: true, message: "请填写项目地址", trigger: ["blur", "change"] }],
-    reflectName: [{ required: true, message: "请填写报修人", trigger: ["blur", "change"] }],
+    reflectName: [{ required: true, message: `请填写${jd.value ? '填报人' : '报修人'}`, trigger: ["blur", "change"] }],
     reflectPhone: [
       { required: true, message: "请填写手机号", trigger: ["blur", "change"] },
       { type: "string", min: 11, required: true, message: "请填写正确11位手机号", pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, trigger: ["blur", "change"] },
     ],
-    repairContent: [{ required: true, message: "请填写问题描述", trigger: ["blur", "change"] }],
+    repairContent: [{ required: true, message: `请填写${jd.value ? '描述' : '问题描述'}`, trigger: ["blur", "change"] }],
   },
 
   actionShow: false,
@@ -200,6 +201,15 @@ onLoad((options) => {
   if ("statusBool" in options) {
     document.getElementsByClassName("uni-page-head-hd")[0].style.cssText = "display: none;";
   }
+  if(jd.value){
+    wx.setNavigationBarTitle({
+      title: "售后服务"
+    });
+  }else{
+    wx.setNavigationBarTitle({
+      title: "报修申请"
+    });
+  }
 });
 
 onReady(() => {});

+ 14 - 3
src/pages/business/fireIot/repairReport/record.vue

@@ -26,8 +26,8 @@
           </view>
           <view class="content-area-row_wrap menu-item">
             <view class="content-area-row_wrap-view"> 项目名称:{{ base.projectName }} </view>
-            <view class="content-area-row_wrap-view"> 报修人:{{ base.reflectName }} </view>
-            <view class="content-area-row_wrap-view"> 报修人电话:{{ base.reflectPhone }} </view>
+            <view class="content-area-row_wrap-view"> {{ jd ? "填报" : "报修" }}人:{{ base.reflectName }} </view>
+            <view class="content-area-row_wrap-view"> {{ jd ? "填报" : "报修" }}人电话:{{ base.reflectPhone }} </view>
             <view class="content-area-row_wrap-view"> 报修内容:{{ base.repairContent }} </view>
             <view class="content-area-row_wrap-view"> 报修地址:{{ base.projectAddress }} </view>
           </view>
@@ -44,10 +44,11 @@ import { getToken, setToken, removeToken } from "@/utils/auth";
 import { useStores, commonStores } from "@/store/modules/index";
 
 import { getHistory } from "@/api/business/fireIot/repairReport.js";
-
+import config from "@/config";
 const { proxy } = getCurrentInstance();
 const useStore = useStores();
 const commonStore = commonStores();
+const jd = ref(config.baseUrl.indexOf("manager.juedatech.com") > -1) //觉大环境判断
 
 const dataList = ref([]);
 const dataStatus = ref(false);
@@ -121,6 +122,16 @@ onLoad((options) => {
   } else {
     init();
   }
+
+  if(jd.value){
+    wx.setNavigationBarTitle({
+      title: "历史记录"
+    });
+  }else{
+    wx.setNavigationBarTitle({
+      title: "报修历史"
+    });
+  }
 });
 </script>
 

+ 2 - 2
src/pages/business/zhaf/xunJian/plan/components/siteDetails.vue

@@ -67,8 +67,7 @@
 
         <view class="bg-white p15 mb15">
           <uni-section class="block mb10" title="点位分布" type="line"></uni-section>
-
-          <u-image width="100%" :src="siteList.pictureUrl"></u-image>
+          <u-image width="100%" :src="siteList.pictureUrl || exampleImage"></u-image>
         </view>
       </view>
       <view class="app-button-fixed">
@@ -86,6 +85,7 @@ import { ref, onMounted, reactive, computed, getCurrentInstance, toRefs, inject,
 /*----------------------------------接口引入-----------------------------------*/
 import { recordList, recordOption, siteDetails } from "@/api/business/zhaf/xunJian/plan.js";
 /*----------------------------------组件引入-----------------------------------*/
+import exampleImage from "@/static/images/xunjian/exampleImage.png"
 /*----------------------------------store引入-----------------------------------*/
 import { useStores, commonStores, xunJianStores } from "@/store/modules/index";
 /*----------------------------------公共方法引入-----------------------------------*/

+ 1 - 0
src/pages/business/zhaf/xunJian/plan/index.vue

@@ -183,6 +183,7 @@ function reportClick(obj) {
   if (tabPosition.value == 0) {
     xunJianStore.planSonId = obj.id;
     xunJianStore.planId = obj.planId;
+    xunJianStore.inspectionStatus = 1;
     uni.navigateTo({
       url: "/pages/business/zhaf/xunJian/plan/components/report",
     });

+ 38 - 12
src/pages/common/evaluate/index.vue

@@ -9,10 +9,18 @@
     :refresherBackground="'#f5f6f7'"
     :data-theme="'theme-' + proxy.$settingStore.themeColor.name"
   >
+  <view v-if="projectName">
     <view class="menu-list">
       <view class="list-cell">
         <view class="menu-item">
-          <view style="font-size: 14px; font-weight: 600"> 为了更好提升我们的服务,请您对我们的服务人员进行评价、留下您宝贵的意见,我们将会不断完善我们的服务。 </view>
+          <view style="font-size: 14px"> 
+            为了更好提升我们的服务,请您对我们的服务人员在 <span style="font-weight: 600;font-size: 16px;">{{ projectName }}</span> 项目上的服务进行评价、留下您宝贵的意见,我们将会不断完善我们的服务。 
+          </view>
+        </view>
+        <view class="menu-item" v-if="handleTime">
+          <view style="font-size: 14px;margin-top:10px;"> 
+            工单提交时间:{{ handleTime.replace(/T/g, " ")}}
+          </view>
         </view>
       </view>
     </view>
@@ -40,15 +48,26 @@
       </view>
     </view>
 
-    <view class="app-button">
+    <view class="app-button" v-if="!rateValue">
       <view class="app-button-padding"></view>
       <view class="app-button-fixed">
         <u-button class="app-buttom" type="primary" @click="handleSubmit('提交')" shape="circle"> 提交 </u-button>
       </view>
     </view>
+  </view>
+  <view v-if="!projectName">
+    <view class="menu-list">
+      <view class="list-cell">
+        <view class="menu-item">
+          <view style="font-size: 14px"> 
+            服务评价编号有误,请核对服务评价页面地址是否正确。
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
   </oa-scroll>
 </template>
-
 <script setup>
 import config from "@/config";
 import { onLoad, onShow, onReady, onHide, onLaunch, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
@@ -56,7 +75,7 @@ import { ref, reactive, computed, getCurrentInstance, toRefs, inject } from "vue
 import { useStores, commonStores } from "@/store/modules/index";
 
 import { score } from "@/api/common/index.js";
-
+import { page } from "@/api/business/fireIot/repairManage.js";
 const { proxy } = getCurrentInstance();
 const commonStore = commonStores();
 
@@ -66,8 +85,10 @@ const data = reactive({
   textareaValue: "",
   repairCode: "",
   statusBool: true,
+  handleTime: "",
+  projectName:"",
 });
-const { rateCount, rateValue, textareaValue, repairCode, statusBool } = toRefs(data);
+const { rateCount, rateValue, textareaValue, repairCode, statusBool, handleTime, projectName } = toRefs(data);
 
 /**
  * @提交
@@ -94,15 +115,20 @@ onLoad((options) => {
     repairCode.value = options.repairCode;
   }
 
-  score({
+  page({
     repairCode: repairCode.value,
+    current: 1,
+    size: 1,
   })
-    .then((requset) => {})
-    .catch((error) => {
-      //#ifdef H5
-      window.history.back();
-      //#endif
-    });
+    .then((requset) => {
+      if(requset.data?.records.length>0){
+        rateValue.value = requset.data.records[0].score;
+        projectName.value = requset.data.records[0].projectName;
+        handleTime.value = requset.data.records[0].handleTime;
+        textareaValue.value = requset.data.records[0].appraiseContent;
+      }
+    })
+
 });
 
 onReady(() => {});

+ 13 - 13
src/pages/index.vue

@@ -94,17 +94,19 @@
       </view>
     </template>
   </oa-scroll>
-  <uni-drawer ref="showLeft" mode="left" style="height: calc(100vh - 44px); width: 90%; margin-top: 44px">
-    <view class="unit">
-      <view class="unit-title">切换企业</view>
-      <view :class="item.id == useStore.tenantId ? 'active' : ''" class="list" v-for="(item, index) in tenantIdList" :key="index" @click="changeTenantId(item.id)">
-        <image class="list-image" src="@/static/images/index/unit-active.png" v-if="item.id == useStore.tenantId"></image>
-        <image class="list-image" src="@/static/images/index/unit.png" v-if="item.id != useStore.tenantId"></image>
-        <text class="list-name">{{ item.tenantName }}</text>
-        <image class="list-right" src="@/static/images/index/right.png" v-if="item.id == useStore.tenantId"></image>
-        <!-- <text class="list-state">默认企业</text> -->
+  <uni-drawer ref="showLeft" mode="left" style="height: calc(100vh - 40px); width: 90vw; margin-top: 44px;" :disableScroll="false">
+    <scroll-view style="height: calc(100% - 4px);width:100vw;background:#0d2e59;" scroll-y="true">
+      <view class="unit">
+        <view class="unit-title">切换企业</view>
+            <view :class="item.id == useStore.tenantId ? 'active' : ''" class="list" v-for="(item, index) in tenantIdList" :key="index" @click="changeTenantId(item.id)">
+              <image class="list-image" src="@/static/images/index/unit-active.png" v-if="item.id == useStore.tenantId"></image>
+              <image class="list-image" src="@/static/images/index/unit.png" v-if="item.id != useStore.tenantId"></image>
+              <text class="list-name">{{ item.tenantName }}</text>
+              <image class="list-right" src="@/static/images/index/right.png" v-if="item.id == useStore.tenantId"></image>
+              <!-- <text class="list-state">默认企业</text> -->
+        </view>
       </view>
-    </view>
+    </scroll-view>
   </uni-drawer>
   <oa-tabbar :tabbarValue="0" :tabbarList="proxy.$constData.homeTabbar"></oa-tabbar>
 </template>
@@ -171,6 +173,7 @@ function getTenantList(id) {
   getTenantByUser(id).then((res) => {
     tenantIdList.value = res.data;
     if (storage.get("account")?.userName && storage.get("account")?.passWord) {
+      tenantIdList.value = res.data
       accountState.value = true;
     }
   });
@@ -552,9 +555,6 @@ onShow(() => {
   width: 100vw !important;
   height: 100%;
   background: #0d2e59;
-  position: fixed;
-  top: 0px;
-  left: 0%;
   &-title {
     margin: 15px 0 10px 10px;
     color: #fff;

+ 1 - 1
src/permission.js

@@ -18,7 +18,7 @@ const whiteList = [
   "/pages/common/phoneVerify/index",//手机号验证
   "/pages/business/fireIot/repairReport/index",//报修申请
   "/pages/business/fireIot/repairReport/record",//报修历史
-  "/pages/common/evaluate/record",//服务评价
+  "/pages/common/evaluate/index",//服务评价
   "/pages/common/NFC/index",//NFC读取
   "/pages/common/appMessage/details",//消息详情
 ];

+ 1 - 1
src/plugins/jsencrypt.js

@@ -1,4 +1,4 @@
-import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
+import JSEncrypt from 'jsencrypt'
 
 // 密钥对生成 http://web.chacuo.net/netrsakeypair
 

BIN
src/static/images/xunjian/exampleImage.png