JavaScript 打怪升级 —— 把业务逻辑当练习题做

1.前言

开发项目和出没社区有一段时间了,会遇上一些比较有印象业务需求。这些业务需求,可能是自己开发项目遇上的,可能是在社区看到的业务需求,或者其他情况接触到的需求,但是这些业务需求的实现逻辑都值得一写。因为这些业务逻辑可以当做练习题一样,可以给大家练手。也希望大家从这些需求实现的逻辑里面可以能到javascript的相关知识,当然如果大家觉得代码需要怎样优化,或者有什么建议,更好的实现方案,觉得我哪里写错了,或者有觉得可以分享的需求,可以在评论提下!

2.月份坐标轴

这个需求是,看下图就懂了

实现方式其实很简单,我在代码打上注释,大家就懂了!

  1. var _date=[],dateData=["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"];
  2. //准备一个月份反转的数组
  3. var dateDataRet=Object.assign([],dateData).reverse();
  4. //获取当前年份
  5. var yearText=new Date().getFullYear();
  6. //获取当前月份 调试的时候,大家可以通过调整now调试 3月-now=2,12月now=11...
  7. var now=new Date().getMonth();
  8. for(let i=0;i<6;i++){
  9. if(now-i<0){
  10. //如果now-i<0,从dateDataRet里面拿数据,下标=|now-i|-1。
  11. _date.push(yearText-1+'年'+dateDataRet[Math.abs(now-i)-1]);
  12. }
  13. else{
  14. //从dateData里面拿数据,下标=now-i
  15. _date.push(yearText+'年'+dateData[now-i]);
  16. }
  17. }
  18. _date.reverse();

可能大家看着会懵,直接看下面的循环图就懂了

3.数值区间

如下图,就是几个数值区间,而且会有一个最小值和最大值

  1. var _min=5,_max=50;
  2. function checkArr(arr,min,max){
  3. //排序
  4. arr.sort(function(n1,n2){return n1.min-n2.min})
  5. //遍历
  6. for(var i=0;i<arr.length;i++){< span=""></arr.length;i++){<>
  7. //区间的最小值不能大于等于区间最大值
  8. if(arr[i].min>=arr[i].max){
  9. console.log('区间的最小值不能大于等于区间最大值');
  10. return;
  11. }
  12. //区间的最小值不能小于默认最小值
  13. if(arr[i].min<min){< span=""></min){<>
  14. console.log('区间的最小值不能小于默认最小值');
  15. return;
  16. }
  17. //区间的最大值不能大于默认最大值
  18. if(arr[i].max>max){
  19. console.log('区间的最大值不能大于默认最大值');
  20. return;
  21. }
  22. //元素对比,从第二个元素开始
  23. if(i>0){
  24. //minInclude,maxInclude,为false就是不包含,为true就是包含
  25. //{min:10,max:20,minInclude:false,maxInclude:false}
  26. //等同于(10,20)
  27. //{min:20,max:30,minInclude:true,maxInclude:false}
  28. //等同于[20,30);
  29. //如果前一个的最大值和当前的最小值都是包含情况,那么当前区间的最小值一定要比前一个区间的最大值大1
  30. if(arr[i].minInclude&&arr[i-1].maxInclude&&arr[i].min-arr[i-1].max!==1){
  31. console.log('取值范围错误-当前区间的最小值和前一个区间的最大值都是包含情况,当前区间的最小值一定要比前一个区间的最大值大1');
  32. return;
  33. }
  34. //如果前一个的最大值和当前的最小值。一个是包含,一个是不包含,那么当前区间的的最小值一定要等于上一个区间的最大值
  35. else if(arr[i].minInclude!==arr[i-1].maxInclude&&arr[i].min!==arr[i-1].max){
  36. console.log('取值范围错误-当前区间的最小值和前一个区间的最大值其中一个是包含,一个是不包含情况,当前区间的最小值一定要等于前一个区间的最大值');
  37. return;
  38. }
  39. //如果前一个的最大值和当前的最小值都是不包含,肯定不满足
  40. else if((!arr[i].minInclude)&&(!arr[i-1].maxInclude)){
  41. console.log('取值范围错误-前一个的最大值和当前的最小值都是不包含情况,不满足收尾相连');
  42. return;
  43. }
  44. }
  45. }
  46. }

测试用例

  1. var arr1=[{min:10,max:20,minInclude:false,maxInclude:true},{min:21,max:30,minInclude:true,maxInclude:true}],
  2. arr2=[{min:10,max:20,minInclude:false,maxInclude:true},{min:20,max:30,minInclude:true,maxInclude:false}],
  3. arr3=[{min:10,max:20,minInclude:false,maxInclude:true},{min:20,max:30,minInclude:false,maxInclude:false}],
  4. arr4=[{min:10,max:20,minInclude:false,maxInclude:false},{min:20,max:30,minInclude:true,maxInclude:false}],
  5. arr5=[{min:10,max:20,minInclude:false,maxInclude:false},{min:21,max:30,minInclude:true,maxInclude:false}],
  6. arr6=[{min:10,max:20,minInclude:false,maxInclude:false},{min:15,max:30,minInclude:false,maxInclude:false}],
  7. arr7=[{min:10,max:20,minInclude:false,maxInclude:false},{min:20,max:30,minInclude:false,maxInclude:false}],
  8. arr8=[{min:1,max:20,minInclude:false,maxInclude:false},{min:20,max:30,minInclude:false,maxInclude:false}],
  9. arr9=[{min:20,max:20,minInclude:false,maxInclude:false},{min:20,max:30,minInclude:false,maxInclude:false}],
  10. arr10=[{min:20,max:30,minInclude:false,maxInclude:false},{min:20,max:70,minInclude:false,maxInclude:false}];

运行结果

4.数组对比

这个基于我回答过的一个问题,现在化用,改写一下

JavaScript如何对比两个数组?数组B根据数组A来做出增删? (不用jquery,原生js)

具体问题是这样的:

arryA

  1. var arrayA = ['a','b','c'];

arryB

  1. var arrayB = [{
  2. key:'a',
  3. num1:'1',
  4. num2:'2',
  5. num3:'3',
  6. tot:'6'
  7. },{
  8. key:'b',
  9. num1:'11',
  10. num2:'22',
  11. num3:'33',
  12. tot:'66'
  13. },{
  14. key: 'c',
  15. num1: '111',
  16. num2: '222',
  17. num3: '333',
  18. tot:666
  19. }];

1、如果arryA中有a,arryB中没有,那么在arryB中增加一个key值为a的boj,且其他属性值可均为'0';如下: {key:'a',num1:'0',num2:'0',num3:'0',tot':0'}

2、如果arryA中有a,arryB中也有key值为a的obj,那么arryB则不改变,并且该obj里的其他属性和属性值均不变;

3、如果在arryA中删除了a,那么arryB中key值为a的obj整个删掉。

  1. //准备临时数组
  2. function compareArr(arr1,arr2){
  3. var result=[],arr;
  4. //遍历
  5. for(var i=0;i<arr1.length;i++){< span=""></arr1.length;i++){<>
  6. //根据arr1[i]的值,查找arrayB,如果arr2中的有满足条件(arrayB中的对象,有key值等于arrayA[i])的项,就会返回满足条件的项,否则返回underfind;
  7. arr=arr2.find(function(val){return val.key===arr1[i]});
  8. //如果arr不是undefind,就会添加arr,否则添加{key:arrayA[i],num1:'0',num2:'0',num3:'0',tot:'0'}。
  9. arr?result.push(arr):result.push({key:arrayA[i],num1:'0',num2:'0',num3:'0',tot:'0'});
  10. }
  11. }

测试

  1. var arrayA = ['b','c'];
  2. var arrayB = [{
  3. key:'a',
  4. num1:'1',
  5. num2:'2',
  6. num3:'3',
  7. tot:'6'
  8. },{
  9. key:'b',
  10. num1:'11',
  11. num2:'22',
  12. num3:'33',
  13. tot:'66'
  14. },{
  15. key: 'c',
  16. num1: '111',
  17. num2: '222',
  18. num3: '333',
  19. tot:666
  20. }];
  21. compareArr(arrayA,arrayB);

5.学院获奖

统计学生申请优秀毕业生,并且符合条件的(成绩优秀,拿过奖学金,获得过三好学生)。前提是要申请

大概的流程图就是像下面这样!

我在代码上写上注释,相信不难理解了

  1. //学生列表
  2. //isApply:是否有申请优秀毕业生
  3. let studentList = [
  4. {
  5. name: 'aa',
  6. isApply: false,
  7. id: 1
  8. },
  9. {
  10. name: 'bb',
  11. isApply: true,
  12. id: 2
  13. },
  14. {
  15. name: 'cc',
  16. isApply: true,
  17. id: 3
  18. }
  19. ];
  20. //申请优秀毕业生的学生 isApply:true
  21. let _student = studentList.filter(function (item) {
  22. return item.isApply;
  23. });
  24. //isExcellent:优秀学生的id列表
  25. //isScholarship:获得过奖学金的学生的id列表
  26. //isThreeGood:获得过三好学生的学生的id列表
  27. //accord:集合
  28. let isExcellent = [1, 2, 3, 4, 5], isScholarship = [4, 2, 5, 6, 2, 1, 2], isThreeGood = [2, 1, 4, 52, 36], accord = [];
  29. //数组去重函数
  30. function removeRepeatArr(arr) {
  31. return arr.filter(function (item, index, self) {
  32. return self.indexOf(item) === index;
  33. });
  34. }
  35. //统计数组中,一个遇上元素的出现次数
  36. function getEleCount(obj, ele) {
  37. let num = 0;
  38. for (let i = 0, len = obj.length; i < len; i++) {
  39. if (ele === obj[i]) {
  40. num++;
  41. }
  42. }
  43. return num;
  44. }
  45. //添加学生记录,把获得成绩优秀的学生的id,获得过奖学金的学生的id,获得过三好学生的id添加进去。
  46. //但是添加之前,要对获得成绩优秀的学生的id,获得过奖学金的学生的id,获得过三好学生的id。这个三个数组进行去重再添加进accord,因为一个学生可能不止一次成绩优秀,不止一次获得过奖学金,不止一次获得过三好学生
  47. //这样就方便下面的判断,只要学生的id在accord里面出现两次及以上就符合条件
  48. accord.push.apply(accord, removeRepeatArr(isExcellent));
  49. accord.push.apply(accord, removeRepeatArr(isScholarship));
  50. accord.push.apply(accord, removeRepeatArr(isThreeGood));
  51. console.log(accord);
  52. //符合条件的学生列表
  53. let accordStudent = [];
  54. for (let i = 0; i < _student.length; i++) {
  55. //只要学生的id在accord里面出现两次及以上
  56. if (getEleCount(accord, _student[i].id) >= 2) {
  57. //记录哪些学生符合条件
  58. accordStudent.push(_student[i]);
  59. }
  60. }
  61. console.log(accordStudent);

6.数组连续的最大长度

这个也是出于我回答过的问题:如下

  1. //假如有一个数组,下面这个数组最大的连续长度就是4——————8,9,10,11
  2. var arr=[1,2,4,5,6,8,9,10,11];
  3. //代码实现
  4. function countLen(arr){
  5. //如果参数不是数组或者长度为0,直接返回0
  6. if(arr.constructor!==Array||arr.length===0){return 0;}
  7. //首先进入当前连续长度nowLen设初始化为1,最大连续长度maxLen初始化为0
  8. var nowLen=1,maxLen=0;
  9. for(var i=1,len=arr.length;i<len;i++){< span=""></len;i++){<>
  10. //当前数组元素是不是比上一个数组大1
  11. if(arr[i]-arr[i-1]===1){
  12. //如果是,当前连续长度nowLen+1
  13. nowLen++;
  14. }
  15. else{
  16. //否则先判断,当前连续长度是否大于最大连续长度
  17. if(maxLen<nowlen){< span=""></nowlen){<>
  18. //如果是就赋值
  19. maxLen=nowLen
  20. }
  21. //当前连续长度初始化为1
  22. nowLen=1;
  23. }
  24. }
  25. //循环完再判断一次当前连续长度是否大于最大连续长度(避免最大连续长度是数组最后面几个数组时产生的bug)
  26. if(maxLen<nowlen){< span=""></nowlen){<>
  27. maxLen=nowLen
  28. }
  29. //返回最大连续长度
  30. return maxLen;
  31. }

7.答题连对数

这个和上面的代码基本一样,只是判断条件毫厘之差,直接贴,大家看就好

  1. function countTrue(arr){debugger;
  2. //如果参数不是数组或者长度为0,直接返回0
  3. if(arr.constructor!==Array||arr.length===0){return 0;}
  4. //首先初始化连续答对长度nowLen为0,最大连续答对长度maxLen为0
  5. var nowLen=0,maxLen=0;
  6. for(var i=0,len=arr.length;i<len;i++){< span=""></len;i++){<>
  7. //当前数组元素是不是比上一个数组大1
  8. if(arr[i]){
  9. //如果是,当前连续长度nowLen+1
  10. nowLen++;
  11. }
  12. else{
  13. //否则先判断,当前连续长度是否大于最大连续长度
  14. if(maxLen<nowlen){< span=""></nowlen){<>
  15. //如果是就赋值
  16. maxLen=nowLen
  17. }
  18. //当前连续长度初始化为0
  19. nowLen=0;
  20. }
  21. }
  22. //循环完再判断一次当前连续长度是否大于最大连续长度(避免最大连续长度是数组最后面几个数组时产生的bug)
  23. if(maxLen<nowlen){< span=""></nowlen){<>
  24. maxLen=nowLen
  25. }
  26. //返回最大连续长度
  27. return maxLen;
  28. }

8.命名方式转换

比如驼峰命名方式转'-'命名方式。

  1. var str = "shouHou";
  2. //$1-第一个括号匹配的内容
  3. //这个实例,$1='H'
  4. str = str.replace(/([A-Z])/g,"-$1").toLowerCase();

比如'-'命名方式转驼峰命名方式

  1. var str="shou-hou";
  2. //$0-匹配的结果 $1-第一个括号匹配的内容
  3. //这个实例$0='-h' $1='h'
  4. str=str.replace(/-(\w)/g,function($0,$1){
  5. return $1.toUpperCase();
  6. });

9.格式化字符

这个最常见的就是在金额方面的显示需求上,比如后台返回10000。前端要显示成10,000或者其他格式等!

  1. //str
  2. //size-每隔几个字符进行分割 默认3
  3. //delimiter-分割符 默认','
  4. function formatText(str,size,delimiter){
  5. var _str=str.toString();
  6. var _size=size||3,_delimiter=delimiter||',';
  7. /*
  8. 如果_size是3
  9. "\d{1,3}(?=(\d{3})+$)"
  10. */
  11. var regText='\\d{1,'+_size+'}(?=(\\d{'+_size+'})+$)';
  12. /*
  13. /\d{1,3}(?=(\d{3})+$)/g 这个正则的意思:匹配连续的三个数字,但是这些三个数字不能是字符串的开头1-3个字符
  14. */
  15. var reg=new RegExp(regText,'g');
  16. /*
  17. (-?) 匹配前面的-号 (\d+)匹配中间的数字 ((\.\d+)?)匹配小数点后面的数字
  18. //$0-匹配结果,$1-第一个括号返回的内容----(-?) $2,$3如此类推
  19. */
  20. return _str.replace(/^(-?)(\d+)((\.\d+)?)$/, function ($0, $1, $2, $3) {
  21. return $1 + $2.replace(reg, '$&,') + $3;
  22. })
  23. }

10.对象合并,并且记录异常数据

这个需求,可能大家有点懵。下面实例分析 比如有两个都地方记录了我的信息

  1. let info1={
  2. name:"守候",
  3. sex:"男",
  4. age:24,
  5. job:"web前端"
  6. },info2={
  7. name:"守候!",
  8. country:"china",
  9. interest:"basketball",
  10. phone:"12345678910",
  11. job:"web前端"
  12. }

现在要合并我的信息,并且记录可能有异常的信息。比如上面的name属性,在两个对象都有,而且两个对象的值不一样,那么就不知道到底是info1中的name属性是正确的,还是info2中的name属性是正确的。所以,就得把name这个属性记录起来,方便以后核对name这个属性。

如下图

下面,一步一步来,先不管3721,直接合并属性

  1. let objAll={};
  2. function assignObj(objArr) {
  3. let _obj={};
  4. for(let i=0;i<objarr.length;i++){< span=""></objarr.length;i++){<>
  5. _obj=Object.assign(_obj,objArr[i],{});
  6. }
  7. return JSON.parse(JSON.stringify(_obj));
  8. }
  9. objAll=assignObj([objA,objB]);

然后先准备一个字段,记录哪些异常信息

  1. objAll.warnInfo=[];

最后检查对象,判断哪些信息有异常

  1. function checkObj(_objAll,objList) {
  2. //获取所有属性
  3. let _keys=Object.keys(_objAll);
  4. for(let i=0;i<objlist.length;i++){< span=""></objlist.length;i++){<>
  5. for(let j=0;j<_keys.length;j++){
  6. //如果_keys[j]这个属性,在objList[i]和_objAll里面都存在,而且这两个值是不一样的,那么就是一场数据,需要记录!
  7. if(objList[i][_keys[j]]!==undefined&&_objAll[_keys[j]]!==objList[i][_keys[j]]){
  8. _objAll.isError.push(_keys[j]);
  9. }
  10. }
  11. }
  12. return _objAll;
  13. }
  14. console.log(checkObj(objAll,[objA,objB]));

11.筛选标签

如下图,在下面渲染这个标签

大家可能第一可能觉得压根没难度,就是一个对象数组:比如

  1. var searchTag=[
  2. {label:'产品编码',value:'100072236-8'},
  3. {label:'产品名称',value:'甘油'}
  4. ]

但是这样的数据,显然是要经过处理生成的,因为不可能这样发送请求

  1. http://example.com?产品编码=100072236-8

发送过去的参数应该是这样的

  1. http://example.com?proId=100072236-8
  2. var searchParam={proId:'100072236-8',proName:'甘油'}

怎么进行数据的处理呢,其实很简单,代码不打注释,我想都看得懂

  1. var searchTag=[];
  2. var searchText={proId:'产品编码',proName:'产品名称'};
  3. var searchParam={proId:'100072236-8',proName:'甘油'};
  4. Object.keys(searchParam).forEach(function (item) {
  5. searchTag.push({
  6. label:searchText[item],
  7. key:item,
  8. value:searchParam[item]
  9. })
  10. })
  11. console.log(searchTag)

有了这些数据,渲染到页面这个就简单了!

12.导入excel内容

就是excel上这样的内容

转成下面的数据

目录如下

下面开始写代码,我们利用node.js来写

  1. let path = require('path');
  2. //使用ejsexcel读取excel文件 npm install ejsexcel --save
  3. let ejsExcel=require('ejsexcel');
  4. let fs=require('fs');
  5. //读取excel
  6. let exBuf=fs.readFileSync(__dirname+'/resource/userList.xlsx');
  7. let _data=[];
  8. //获取成功后
  9. ejsExcel.getExcelArr(exBuf).then(exlJson=>{
  10. //获取excel数据
  11. let workBook=exlJson;
  12. //获取excel第一张表 sheet1
  13. let workSheets=workBook[0];
  14. //导出js的路径
  15. let newfilepath=path.join(__dirname,"/resource/test.js");
  16. //遍历第一张表的的每一行数据
  17. workSheets.forEach((item,index)=>{
  18. //从第二行开始插入,避免连表头也插入_data里面
  19. if(index>0){
  20. //往_data插入单元格个值,item[0]相当于excel中的姓名,item[1]就是excel中的联系电话
  21. _data.push({
  22. name:item[0],
  23. phone:item[1]
  24. })
  25. }
  26. });
  27. //写入js文件
  28. fs.writeFileSync(newfilepath, 'let _data='+JSON.stringify(_data)+';export {_data}');
  29. }).catch(error=>{
  30. //打印获取失败信息
  31. console.log("读取错误!");
  32. console.log(error);
  33. });

然后命令行执行该js

  1. $ node importFile.js

然后就发现多了一个test.js文件

excel的数据就这样导入成js的一个数组了,只要引入这个数组,就可以正常的使用了!

13.随机循环

当时接到的业务是实际显示客户的信息,感觉有点像音乐播放器的随机循环。

要求:

  1. 一个提示列表里面,提示的信息每隔500ms随机展示。
  2. 同一轮循环里面,一个提示信息只能展示一次。
  3. 列表的提示信息全部展示完了,进行下一轮展示。

这个逻辑没什么,直接在代码打上注释,我想大家就明白了!

  1. var tipList=['提示1','提示2','提示3','提示4','提示5','提示6','提示7','提示8','提示9'];
  2. var tipListShow=[];
  3. tipListShow=Object.assign([],tipList);
  4. var i=0,timer=;
  5. function play() {
  6. //随机显示一个,显示了之后,把这个项从tipListShow中删除掉,防止在同一轮重复出现!
  7. console.log(tipListShow.splice(Math.floor(Math.random() * tipListShow.length),1)[0]);
  8. //当循环完了之后,tipListShow的长度就会是0,然后就重新赋值,准备进行下一轮的随机循环
  9. if(tipListShow.length===0){
  10. tipListShow=Object.assign([],tipList);
  11. i=0;
  12. }
  13. //如果需要暂停或者停止的,清除这个定时器即可,下次执行就重新这样创建定时器,执行play();!
  14. timer=setTimeout(function () {
  15. play();
  16. },500);
  17. }
  18. play();

14.小结

好了,关于我收集到的一些业务需求逻辑,以及实现的方式,就说到这里了!接触到的也无需求逻辑很多,但是值得写的,可以当做练习题的,就记录到这里了。我上面代码实现可能会有点粗糙,大家有更好的实现方案,欢迎建议一下。如果大家有什么可以当做练习题的需求,可以提下。让大家有多些练习题可以尝试下,学习下!

原文发布于微信公众号 - IT派(transfer_3255716726)

原文发表时间:2018-07-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

Java IAQ:很少被回答的问题

一个问题如果被回答地很少,有可能是因为知道答案的人很少,亦或是因为问题本身模糊不清、微不足道(但对你来讲可能很关键)。我似乎发明了一个术语,但是它在一个信息量很...

1042
来自专栏小俊博客

Nginx的location规则迷之匹配

Nginx,一个改变世界的软件,其作者是一个俄罗斯人,俗称毛子,在国人的印象中,是一群晚饭后牵着大灰熊在小区楼下散步的彪汉。能写出这般顺滑的软件,可谓是心有猛虎...

6652
来自专栏编程

让你比95%的人更懂Pythonic的内置模块:collections

Python的集合(collections)模块,为很多用其他方法很难实现的场景提供了解决方案。 本文我们将会学习该模块的抽象概念是如何产生的,日后处理不同问题...

2015
来自专栏TungHsu

这或许是对小白最友好的python入门了吧——3,数字处理

昨天那篇推文是不是太长了,以后为了大家能够更好地理解,所以我们还是写的少点,大家看完以后要好好练习哦! 不要在此处直接复制代码! 在Python中可以执行对整...

3166
来自专栏Play & Scala 技术分享

挑逗 Java 程序员的那些 Scala 绝技

有个问题一直困扰着 Scala 社区,为什么一些 Java 开发者将 Scala 捧到了天上,认为它是来自上帝之吻的完美语言;而另外一些 Java 开发者却对它...

1766
来自专栏java一日一条

Java集合框架综述

近被陆陆续续问了几遍HashMap的实现,回答的不好,打算复习复习JDK中的集合框架,并尝试分析其源码,这么做一方面是这些类非常实用,掌握其实现能更好的优化我们...

1074
来自专栏深度学习之tensorflow实战篇

Python中的__init__()方法整理中(两种解释)

解释一:看懂了就不用看第二种了 __init__()方法是Python学习当中重要的基础知识,__init__()方法意义重大的原因有两个。第一个原因是在对...

1.1K6
来自专栏编程

Python函数之匿名函数

各位小伙伴,周五快乐! 今天是2017年最后一个工作日,大家都在忙碌些什么呢? 今天我们要讲的是Python函数中的匿名函数 好像函数中的分类及说法很多,但是大...

2126
来自专栏java一日一条

Java集合框架综述

近被陆陆续续问了几遍HashMap的实现,回答的不好,打算复习复习JDK中的集合框架,并尝试分析其源码,这么做一方面是这些类非常实用,掌握其实现能更好的优化我们...

951
来自专栏web前端教室

浅谈数据结构 - 字典

浅淡,真的是很浅。Orz.. 先摆出定义,这里的字典是啥样的? 是以键-值对形式保存数据的一种结构。 现实中比较典型的例子,就是以前的电话本。你想找一个单位的电...

19910

扫码关注云+社区

领取腾讯云代金券