微信小程序接收后台数据

微信小程序中若要接收后台数据,如果不是要云开发的话,需要wx.request来获取后台的数据,但一般都是需要进行函数的封装,

以便实现接口的优化以及代码结构的美化. 注意:wx.request只能用来发送https网络请求。

小程序只能跟指定域名进行网络通信,故需实现来设置通信域名。

不过如果在开发时涉及了多个域名,可在小程序的详情--本地设置中--勾选不校验合法域名、web-view(业务域名)、TLS版本以及Http证书.(勾选后也能来发送http协议的网络请求啦)

需要引入的文件:

request/index.js文件:

 1 let ajaxTimes = 0; //需考虑同时发送的ajax请求,避免影响用户体验
 2 // 专门用来处理优化请求
 3 export const request = (params) => {
 4     ajaxTimes++;
 5     //显示加载效果
 6     wx.showLoading({
 7         title: '加载中',
 8         mask: true, //添加该蒙版后,显示loading时用户无法进行其他操作
 9         success: (result) => {},
10         fail: () => {},
11         complete: () => {}
12     });
13     //定义公共的url
14     const baseUrl = '自己来分析';
15     return new Promise((resolve, reject) => {
16         var reqTask = wx.request({
17             ...params,
18             url: baseUrl + params.url,
19             success: (res) => {
20                 resolve(res.data.message) //此处需根据自己返回数据的统一格式来写  
21             },
22             fail: (err) => {
23                 reject(err)
24             },
25             complete: () => {
26                 if (!(--ajaxTimes))
27                     wx.hideLoading(); //接在数据完后需隐藏加载标识
28             }
29         });
30     })
31 }

引入es7 async回调地狱解决方案 lib/runtime/runtime.js:

  1 /**
  2  * Copyright (c) 2014-present, Facebook, Inc.
  3  *
  4  * This source code is licensed under the MIT license found in the
  5  * LICENSE file in the root directory of this source tree.
  6  */
  7 
  8 var regeneratorRuntime = (function (exports) {
  9   "use strict";
 10 
 11   var Op = Object.prototype;
 12   var hasOwn = Op.hasOwnProperty;
 13   var undefined; // More compressible than void 0.
 14   var $Symbol = typeof Symbol === "function" ? Symbol : {};
 15   var iteratorSymbol = $Symbol.iterator || "@@iterator";
 16   var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
 17   var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
 18 
 19   function wrap(innerFn, outerFn, self, tryLocsList) {
 20     // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
 21     var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
 22     var generator = Object.create(protoGenerator.prototype);
 23     var context = new Context(tryLocsList || []);
 24 
 25     // The ._invoke method unifies the implementations of the .next,
 26     // .throw, and .return methods.
 27     generator._invoke = makeInvokeMethod(innerFn, self, context);
 28 
 29     return generator;
 30   }
 31   exports.wrap = wrap;
 32 
 33   // Try/catch helper to minimize deoptimizations. Returns a completion
 34   // record like context.tryEntries[i].completion. This interface could
 35   // have been (and was previously) designed to take a closure to be
 36   // invoked without arguments, but in all the cases we care about we
 37   // already have an existing method we want to call, so there's no need
 38   // to create a new function object. We can even get away with assuming
 39   // the method takes exactly one argument, since that happens to be true
 40   // in every case, so we don't have to touch the arguments object. The
 41   // only additional allocation required is the completion record, which
 42   // has a stable shape and so hopefully should be cheap to allocate.
 43   function tryCatch(fn, obj, arg) {
 44     try {
 45       return { type: "normal", arg: fn.call(obj, arg) };
 46     } catch (err) {
 47       return { type: "throw", arg: err };
 48     }
 49   }
 50 
 51   var GenStateSuspendedStart = "suspendedStart";
 52   var GenStateSuspendedYield = "suspendedYield";
 53   var GenStateExecuting = "executing";
 54   var GenStateCompleted = "completed";
 55 
 56   // Returning this object from the innerFn has the same effect as
 57   // breaking out of the dispatch switch statement.
 58   var ContinueSentinel = {};
 59 
 60   // Dummy constructor functions that we use as the .constructor and
 61   // .constructor.prototype properties for functions that return Generator
 62   // objects. For full spec compliance, you may wish to configure your
 63   // minifier not to mangle the names of these two functions.
 64   function Generator() { }
 65   function GeneratorFunction() { }
 66   function GeneratorFunctionPrototype() { }
 67 
 68   // This is a polyfill for %IteratorPrototype% for environments that
 69   // don't natively support it.
 70   var IteratorPrototype = {};
 71   IteratorPrototype[iteratorSymbol] = function () {
 72     return this;
 73   };
 74 
 75   var getProto = Object.getPrototypeOf;
 76   var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
 77   if (NativeIteratorPrototype &&
 78     NativeIteratorPrototype !== Op &&
 79     hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
 80     // This environment has a native %IteratorPrototype%; use it instead
 81     // of the polyfill.
 82     IteratorPrototype = NativeIteratorPrototype;
 83   }
 84 
 85   var Gp = GeneratorFunctionPrototype.prototype =
 86     Generator.prototype = Object.create(IteratorPrototype);
 87   GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
 88   GeneratorFunctionPrototype.constructor = GeneratorFunction;
 89   GeneratorFunctionPrototype[toStringTagSymbol] =
 90     GeneratorFunction.displayName = "GeneratorFunction";
 91 
 92   // Helper for defining the .next, .throw, and .return methods of the
 93   // Iterator interface in terms of a single ._invoke method.
 94   function defineIteratorMethods(prototype) {
 95     ["next", "throw", "return"].forEach(function (method) {
 96       prototype[method] = function (arg) {
 97         return this._invoke(method, arg);
 98       };
 99     });
100   }
101 
102   exports.isGeneratorFunction = function (genFun) {
103     var ctor = typeof genFun === "function" && genFun.constructor;
104     return ctor
105       ? ctor === GeneratorFunction ||
106       // For the native GeneratorFunction constructor, the best we can
107       // do is to check its .name property.
108       (ctor.displayName || ctor.name) === "GeneratorFunction"
109       : false;
110   };
111 
112   exports.mark = function (genFun) {
113     if (Object.setPrototypeOf) {
114       Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
115     } else {
116       genFun.__proto__ = GeneratorFunctionPrototype;
117       if (!(toStringTagSymbol in genFun)) {
118         genFun[toStringTagSymbol] = "GeneratorFunction";
119       }
120     }
121     genFun.prototype = Object.create(Gp);
122     return genFun;
123   };
124 
125   // Within the body of any async function, `await x` is transformed to
126   // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
127   // `hasOwn.call(value, "__await")` to determine if the yielded value is
128   // meant to be awaited.
129   exports.awrap = function (arg) {
130     return { __await: arg };
131   };
132 
133   function AsyncIterator(generator) {
134     function invoke(method, arg, resolve, reject) {
135       var record = tryCatch(generator[method], generator, arg);
136       if (record.type === "throw") {
137         reject(record.arg);
138       } else {
139         var result = record.arg;
140         var value = result.value;
141         if (value &&
142           typeof value === "object" &&
143           hasOwn.call(value, "__await")) {
144           return Promise.resolve(value.__await).then(function (value) {
145             invoke("next", value, resolve, reject);
146           }, function (err) {
147             invoke("throw", err, resolve, reject);
148           });
149         }
150 
151         return Promise.resolve(value).then(function (unwrapped) {
152           // When a yielded Promise is resolved, its final value becomes
153           // the .value of the Promise<{value,done}> result for the
154           // current iteration.
155           result.value = unwrapped;
156           resolve(result);
157         }, function (error) {
158           // If a rejected Promise was yielded, throw the rejection back
159           // into the async generator function so it can be handled there.
160           return invoke("throw", error, resolve, reject);
161         });
162       }
163     }
164 
165     var previousPromise;
166 
167     function enqueue(method, arg) {
168       function callInvokeWithMethodAndArg() {
169         return new Promise(function (resolve, reject) {
170           invoke(method, arg, resolve, reject);
171         });
172       }
173 
174       return previousPromise =
175         // If enqueue has been called before, then we want to wait until
176         // all previous Promises have been resolved before calling invoke,
177         // so that results are always delivered in the correct order. If
178         // enqueue has not been called before, then it is important to
179         // call invoke immediately, without waiting on a callback to fire,
180         // so that the async generator function has the opportunity to do
181         // any necessary setup in a predictable way. This predictability
182         // is why the Promise constructor synchronously invokes its
183         // executor callback, and why async functions synchronously
184         // execute code before the first await. Since we implement simple
185         // async functions in terms of async generators, it is especially
186         // important to get this right, even though it requires care.
187         previousPromise ? previousPromise.then(
188           callInvokeWithMethodAndArg,
189           // Avoid propagating failures to Promises returned by later
190           // invocations of the iterator.
191           callInvokeWithMethodAndArg
192         ) : callInvokeWithMethodAndArg();
193     }
194 
195     // Define the unified helper method that is used to implement .next,
196     // .throw, and .return (see defineIteratorMethods).
197     this._invoke = enqueue;
198   }
199 
200   defineIteratorMethods(AsyncIterator.prototype);
201   AsyncIterator.prototype[asyncIteratorSymbol] = function () {
202     return this;
203   };
204   exports.AsyncIterator = AsyncIterator;
205 
206   // Note that simple async functions are implemented on top of
207   // AsyncIterator objects; they just return a Promise for the value of
208   // the final result produced by the iterator.
209   exports.async = function (innerFn, outerFn, self, tryLocsList) {
210     var iter = new AsyncIterator(
211       wrap(innerFn, outerFn, self, tryLocsList)
212     );
213 
214     return exports.isGeneratorFunction(outerFn)
215       ? iter // If outerFn is a generator, return the full iterator.
216       : iter.next().then(function (result) {
217         return result.done ? result.value : iter.next();
218       });
219   };
220 
221   function makeInvokeMethod(innerFn, self, context) {
222     var state = GenStateSuspendedStart;
223 
224     return function invoke(method, arg) {
225       if (state === GenStateExecuting) {
226         throw new Error("Generator is already running");
227       }
228 
229       if (state === GenStateCompleted) {
230         if (method === "throw") {
231           throw arg;
232         }
233 
234         // Be forgiving, per 25.3.3.3.3 of the spec:
235         // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
236         return doneResult();
237       }
238 
239       context.method = method;
240       context.arg = arg;
241 
242       while (true) {
243         var delegate = context.delegate;
244         if (delegate) {
245           var delegateResult = maybeInvokeDelegate(delegate, context);
246           if (delegateResult) {
247             if (delegateResult === ContinueSentinel) continue;
248             return delegateResult;
249           }
250         }
251 
252         if (context.method === "next") {
253           // Setting context._sent for legacy support of Babel's
254           // function.sent implementation.
255           context.sent = context._sent = context.arg;
256 
257         } else if (context.method === "throw") {
258           if (state === GenStateSuspendedStart) {
259             state = GenStateCompleted;
260             throw context.arg;
261           }
262 
263           context.dispatchException(context.arg);
264 
265         } else if (context.method === "return") {
266           context.abrupt("return", context.arg);
267         }
268 
269         state = GenStateExecuting;
270 
271         var record = tryCatch(innerFn, self, context);
272         if (record.type === "normal") {
273           // If an exception is thrown from innerFn, we leave state ===
274           // GenStateExecuting and loop back for another invocation.
275           state = context.done
276             ? GenStateCompleted
277             : GenStateSuspendedYield;
278 
279           if (record.arg === ContinueSentinel) {
280             continue;
281           }
282 
283           return {
284             value: record.arg,
285             done: context.done
286           };
287 
288         } else if (record.type === "throw") {
289           state = GenStateCompleted;
290           // Dispatch the exception by looping back around to the
291           // context.dispatchException(context.arg) call above.
292           context.method = "throw";
293           context.arg = record.arg;
294         }
295       }
296     };
297   }
298 
299   // Call delegate.iterator[context.method](context.arg) and handle the
300   // result, either by returning a { value, done } result from the
301   // delegate iterator, or by modifying context.method and context.arg,
302   // setting context.delegate to null, and returning the ContinueSentinel.
303   function maybeInvokeDelegate(delegate, context) {
304     var method = delegate.iterator[context.method];
305     if (method === undefined) {
306       // A .throw or .return when the delegate iterator has no .throw
307       // method always terminates the yield* loop.
308       context.delegate = null;
309 
310       if (context.method === "throw") {
311         // Note: ["return"] must be used for ES3 parsing compatibility.
312         if (delegate.iterator["return"]) {
313           // If the delegate iterator has a return method, give it a
314           // chance to clean up.
315           context.method = "return";
316           context.arg = undefined;
317           maybeInvokeDelegate(delegate, context);
318 
319           if (context.method === "throw") {
320             // If maybeInvokeDelegate(context) changed context.method from
321             // "return" to "throw", let that override the TypeError below.
322             return ContinueSentinel;
323           }
324         }
325 
326         context.method = "throw";
327         context.arg = new TypeError(
328           "The iterator does not provide a 'throw' method");
329       }
330 
331       return ContinueSentinel;
332     }
333 
334     var record = tryCatch(method, delegate.iterator, context.arg);
335 
336     if (record.type === "throw") {
337       context.method = "throw";
338       context.arg = record.arg;
339       context.delegate = null;
340       return ContinueSentinel;
341     }
342 
343     var info = record.arg;
344 
345     if (!info) {
346       context.method = "throw";
347       context.arg = new TypeError("iterator result is not an object");
348       context.delegate = null;
349       return ContinueSentinel;
350     }
351 
352     if (info.done) {
353       // Assign the result of the finished delegate to the temporary
354       // variable specified by delegate.resultName (see delegateYield).
355       context[delegate.resultName] = info.value;
356 
357       // Resume execution at the desired location (see delegateYield).
358       context.next = delegate.nextLoc;
359 
360       // If context.method was "throw" but the delegate handled the
361       // exception, let the outer generator proceed normally. If
362       // context.method was "next", forget context.arg since it has been
363       // "consumed" by the delegate iterator. If context.method was
364       // "return", allow the original .return call to continue in the
365       // outer generator.
366       if (context.method !== "return") {
367         context.method = "next";
368         context.arg = undefined;
369       }
370 
371     } else {
372       // Re-yield the result returned by the delegate method.
373       return info;
374     }
375 
376     // The delegate iterator is finished, so forget it and continue with
377     // the outer generator.
378     context.delegate = null;
379     return ContinueSentinel;
380   }
381 
382   // Define Generator.prototype.{next,throw,return} in terms of the
383   // unified ._invoke helper method.
384   defineIteratorMethods(Gp);
385 
386   Gp[toStringTagSymbol] = "Generator";
387 
388   // A Generator should always return itself as the iterator object when the
389   // @@iterator function is called on it. Some browsers' implementations of the
390   // iterator prototype chain incorrectly implement this, causing the Generator
391   // object to not be returned from this call. This ensures that doesn't happen.
392   // See https://github.com/facebook/regenerator/issues/274 for more details.
393   Gp[iteratorSymbol] = function () {
394     return this;
395   };
396 
397   Gp.toString = function () {
398     return "[object Generator]";
399   };
400 
401   function pushTryEntry(locs) {
402     var entry = { tryLoc: locs[0] };
403 
404     if (1 in locs) {
405       entry.catchLoc = locs[1];
406     }
407 
408     if (2 in locs) {
409       entry.finallyLoc = locs[2];
410       entry.afterLoc = locs[3];
411     }
412 
413     this.tryEntries.push(entry);
414   }
415 
416   function resetTryEntry(entry) {
417     var record = entry.completion || {};
418     record.type = "normal";
419     delete record.arg;
420     entry.completion = record;
421   }
422 
423   function Context(tryLocsList) {
424     // The root entry object (effectively a try statement without a catch
425     // or a finally block) gives us a place to store values thrown from
426     // locations where there is no enclosing try statement.
427     this.tryEntries = [{ tryLoc: "root" }];
428     tryLocsList.forEach(pushTryEntry, this);
429     this.reset(true);
430   }
431 
432   exports.keys = function (object) {
433     var keys = [];
434     for (var key in object) {
435       keys.push(key);
436     }
437     keys.reverse();
438 
439     // Rather than returning an object with a next method, we keep
440     // things simple and return the next function itself.
441     return function next() {
442       while (keys.length) {
443         var key = keys.pop();
444         if (key in object) {
445           next.value = key;
446           next.done = false;
447           return next;
448         }
449       }
450 
451       // To avoid creating an additional object, we just hang the .value
452       // and .done properties off the next function object itself. This
453       // also ensures that the minifier will not anonymize the function.
454       next.done = true;
455       return next;
456     };
457   };
458 
459   function values(iterable) {
460     if (iterable) {
461       var iteratorMethod = iterable[iteratorSymbol];
462       if (iteratorMethod) {
463         return iteratorMethod.call(iterable);
464       }
465 
466       if (typeof iterable.next === "function") {
467         return iterable;
468       }
469 
470       if (!isNaN(iterable.length)) {
471         var i = -1, next = function next() {
472           while (++i < iterable.length) {
473             if (hasOwn.call(iterable, i)) {
474               next.value = iterable[i];
475               next.done = false;
476               return next;
477             }
478           }
479 
480           next.value = undefined;
481           next.done = true;
482 
483           return next;
484         };
485 
486         return next.next = next;
487       }
488     }
489 
490     // Return an iterator with no values.
491     return { next: doneResult };
492   }
493   exports.values = values;
494 
495   function doneResult() {
496     return { value: undefined, done: true };
497   }
498 
499   Context.prototype = {
500     constructor: Context,
501 
502     reset: function (skipTempReset) {
503       this.prev = 0;
504       this.next = 0;
505       // Resetting context._sent for legacy support of Babel's
506       // function.sent implementation.
507       this.sent = this._sent = undefined;
508       this.done = false;
509       this.delegate = null;
510 
511       this.method = "next";
512       this.arg = undefined;
513 
514       this.tryEntries.forEach(resetTryEntry);
515 
516       if (!skipTempReset) {
517         for (var name in this) {
518           // Not sure about the optimal order of these conditions:
519           if (name.charAt(0) === "t" &&
520             hasOwn.call(this, name) &&
521             !isNaN(+name.slice(1))) {
522             this[name] = undefined;
523           }
524         }
525       }
526     },
527 
528     stop: function () {
529       this.done = true;
530 
531       var rootEntry = this.tryEntries[0];
532       var rootRecord = rootEntry.completion;
533       if (rootRecord.type === "throw") {
534         throw rootRecord.arg;
535       }
536 
537       return this.rval;
538     },
539 
540     dispatchException: function (exception) {
541       if (this.done) {
542         throw exception;
543       }
544 
545       var context = this;
546       function handle(loc, caught) {
547         record.type = "throw";
548         record.arg = exception;
549         context.next = loc;
550 
551         if (caught) {
552           // If the dispatched exception was caught by a catch block,
553           // then let that catch block handle the exception normally.
554           context.method = "next";
555           context.arg = undefined;
556         }
557 
558         return !!caught;
559       }
560 
561       for (var i = this.tryEntries.length - 1; i >= 0; --i) {
562         var entry = this.tryEntries[i];
563         var record = entry.completion;
564 
565         if (entry.tryLoc === "root") {
566           // Exception thrown outside of any try block that could handle
567           // it, so set the completion value of the entire function to
568           // throw the exception.
569           return handle("end");
570         }
571 
572         if (entry.tryLoc <= this.prev) {
573           var hasCatch = hasOwn.call(entry, "catchLoc");
574           var hasFinally = hasOwn.call(entry, "finallyLoc");
575 
576           if (hasCatch && hasFinally) {
577             if (this.prev < entry.catchLoc) {
578               return handle(entry.catchLoc, true);
579             } else if (this.prev < entry.finallyLoc) {
580               return handle(entry.finallyLoc);
581             }
582 
583           } else if (hasCatch) {
584             if (this.prev < entry.catchLoc) {
585               return handle(entry.catchLoc, true);
586             }
587 
588           } else if (hasFinally) {
589             if (this.prev < entry.finallyLoc) {
590               return handle(entry.finallyLoc);
591             }
592 
593           } else {
594             throw new Error("try statement without catch or finally");
595           }
596         }
597       }
598     },
599 
600     abrupt: function (type, arg) {
601       for (var i = this.tryEntries.length - 1; i >= 0; --i) {
602         var entry = this.tryEntries[i];
603         if (entry.tryLoc <= this.prev &&
604           hasOwn.call(entry, "finallyLoc") &&
605           this.prev < entry.finallyLoc) {
606           var finallyEntry = entry;
607           break;
608         }
609       }
610 
611       if (finallyEntry &&
612         (type === "break" ||
613           type === "continue") &&
614         finallyEntry.tryLoc <= arg &&
615         arg <= finallyEntry.finallyLoc) {
616         // Ignore the finally entry if control is not jumping to a
617         // location outside the try/catch block.
618         finallyEntry = null;
619       }
620 
621       var record = finallyEntry ? finallyEntry.completion : {};
622       record.type = type;
623       record.arg = arg;
624 
625       if (finallyEntry) {
626         this.method = "next";
627         this.next = finallyEntry.finallyLoc;
628         return ContinueSentinel;
629       }
630 
631       return this.complete(record);
632     },
633 
634     complete: function (record, afterLoc) {
635       if (record.type === "throw") {
636         throw record.arg;
637       }
638 
639       if (record.type === "break" ||
640         record.type === "continue") {
641         this.next = record.arg;
642       } else if (record.type === "return") {
643         this.rval = this.arg = record.arg;
644         this.method = "return";
645         this.next = "end";
646       } else if (record.type === "normal" && afterLoc) {
647         this.next = afterLoc;
648       }
649 
650       return ContinueSentinel;
651     },
652 
653     finish: function (finallyLoc) {
654       for (var i = this.tryEntries.length - 1; i >= 0; --i) {
655         var entry = this.tryEntries[i];
656         if (entry.finallyLoc === finallyLoc) {
657           this.complete(entry.completion, entry.afterLoc);
658           resetTryEntry(entry);
659           return ContinueSentinel;
660         }
661       }
662     },
663 
664     "catch": function (tryLoc) {
665       for (var i = this.tryEntries.length - 1; i >= 0; --i) {
666         var entry = this.tryEntries[i];
667         if (entry.tryLoc === tryLoc) {
668           var record = entry.completion;
669           if (record.type === "throw") {
670             var thrown = record.arg;
671             resetTryEntry(entry);
672           }
673           return thrown;
674         }
675       }
676 
677       // The context.catch method must only be called with a location
678       // argument that corresponds to a known catch block.
679       throw new Error("illegal catch attempt");
680     },
681 
682     delegateYield: function (iterable, resultName, nextLoc) {
683       this.delegate = {
684         iterator: values(iterable),
685         resultName: resultName,
686         nextLoc: nextLoc
687       };
688 
689       if (this.method === "next") {
690         // Deliberately forget the last sent value so that we don't
691         // accidentally pass it on to the delegate.
692         this.arg = undefined;
693       }
694 
695       return ContinueSentinel;
696     }
697   };
698 
699   // Regardless of whether this script is executing as a CommonJS module
700   // or not, return the runtime object so that we can declare the variable
701   // regeneratorRuntime in the outer scope, which allows this module to be
702   // injected easily by `bin/regenerator --include-runtime script.js`.
703   return exports;
704 
705 }(
706   // If this script is executing as a CommonJS module, use module.exports
707   // as the regeneratorRuntime namespace. Otherwise create a new empty
708   // object. Either way, the resulting object will be used to initialize
709   // the regeneratorRuntime variable at the top of this file.
710   typeof module === "object" ? module.exports : {}
711 ));
View Code

 

范例:

 1 import {request} from '../../request/index.js'; //需引入request
 2 import regeneratorRuntime from '../../lib/runtime/runtime'; //引入async解决方案  此处需根据自己的路径来写
 3 
 4 //此处示范一个得请求数据的函数
 5 //普通promise请求写法
 6  getCatesList(){
 7      request({url:''})
 8      .then(res=>{
 9          //其他操作
10      })
11  }
12 
13 //async写法  需引入runtime.js文件
14 async getXatesList(){
15     const res=await request({url:''});
16     //然后进行其他操作
17 }

 

posted @ 2020-08-10 12:01  良夜  阅读(3071)  评论(0编辑  收藏  举报