46 changed files with 14433 additions and 6865 deletions
File diff suppressed because it is too large
Load Diff
@ -1,302 +0,0 @@
@@ -1,302 +0,0 @@
|
||||
(globalThis["webpackChunkGoFaster"] = globalThis["webpackChunkGoFaster"] || []).push([["src_renderer_components_SpeedTest_vue"],{ |
||||
|
||||
/***/ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css": |
||||
/*!******************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ |
||||
!*** ./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css ***! |
||||
\******************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ |
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ "./node_modules/css-loader/dist/runtime/noSourceMaps.js"); |
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); |
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ "./node_modules/css-loader/dist/runtime/api.js"); |
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); |
||||
// Imports
|
||||
|
||||
|
||||
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); |
||||
// Module
|
||||
___CSS_LOADER_EXPORT___.push([module.id, ` |
||||
.speed-test[data-v-373f173a] { |
||||
padding: 20px; |
||||
max-width: 600px; |
||||
margin: 0 auto; |
||||
text-align: center; |
||||
} |
||||
button[data-v-373f173a] { |
||||
padding: 10px 20px; |
||||
font-size: 16px; |
||||
background-color: #42b983; |
||||
color: white; |
||||
border: none; |
||||
border-radius: 4px; |
||||
cursor: pointer; |
||||
margin: 20px 0; |
||||
} |
||||
button[data-v-373f173a]:disabled { |
||||
background-color: #cccccc; |
||||
cursor: not-allowed; |
||||
} |
||||
.results[data-v-373f173a] { |
||||
margin-top: 20px; |
||||
padding: 15px; |
||||
background-color: #f5f5f5; |
||||
border-radius: 4px; |
||||
text-align: left; |
||||
} |
||||
.result-item[data-v-373f173a] { |
||||
margin: 10px 0; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
} |
||||
.label[data-v-373f173a] { |
||||
font-weight: bold; |
||||
} |
||||
.value[data-v-373f173a] { |
||||
color: #42b983; |
||||
} |
||||
`, ""]);
|
||||
// Exports
|
||||
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); |
||||
|
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=script&lang=js": |
||||
/*!**********************************************************************************************************************************!*\ |
||||
!*** ./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=script&lang=js ***! |
||||
\**********************************************************************************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.runtime.esm-bundler.js"); |
||||
/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vuex */ "./node_modules/vuex/dist/vuex.esm-bundler.js"); |
||||
|
||||
|
||||
|
||||
|
||||
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ |
||||
name: 'SpeedTest', |
||||
setup() { |
||||
const store = (0,vuex__WEBPACK_IMPORTED_MODULE_1__.useStore)() |
||||
const testing = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) |
||||
const result = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(null) |
||||
|
||||
const startTest = async () => { |
||||
testing.value = true |
||||
result.value = null |
||||
|
||||
// 模拟网络测试 (替换为真实测试逻辑)
|
||||
await new Promise(resolve => setTimeout(resolve, 2000)) |
||||
|
||||
const testResult = { |
||||
download: (Math.random() * 100).toFixed(2), |
||||
upload: (Math.random() * 50).toFixed(2), |
||||
ping: (Math.random() * 100).toFixed(2), |
||||
timestamp: new Date().toISOString() |
||||
} |
||||
|
||||
// 保存结果
|
||||
await store.dispatch('saveTestResult', testResult) |
||||
result.value = testResult |
||||
testing.value = false |
||||
} |
||||
|
||||
return { testing, result, startTest } |
||||
} |
||||
}); |
||||
|
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=template&id=373f173a&scoped=true": |
||||
/*!**************************************************************************************************************************************************************************************************************************!*\ |
||||
!*** ./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=template&id=373f173a&scoped=true ***! |
||||
\**************************************************************************************************************************************************************************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ render: () => (/* binding */ render) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.runtime.esm-bundler.js"); |
||||
|
||||
|
||||
const _hoisted_1 = { class: "speed-test" } |
||||
const _hoisted_2 = ["disabled"] |
||||
const _hoisted_3 = { |
||||
key: 0, |
||||
class: "results" |
||||
} |
||||
const _hoisted_4 = { class: "result-item" } |
||||
const _hoisted_5 = { class: "value" } |
||||
const _hoisted_6 = { class: "result-item" } |
||||
const _hoisted_7 = { class: "value" } |
||||
const _hoisted_8 = { class: "result-item" } |
||||
const _hoisted_9 = { class: "value" } |
||||
|
||||
function render(_ctx, _cache, $props, $setup, $data, $options) { |
||||
return ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_1, [ |
||||
_cache[5] || (_cache[5] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h1", null, "GoFaster Speed Test", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { |
||||
onClick: _cache[0] || (_cache[0] = (...args) => ($setup.startTest && $setup.startTest(...args))), |
||||
disabled: $setup.testing |
||||
}, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.testing ? 'Testing...' : 'Start Test'), 9 /* TEXT, PROPS */, _hoisted_2), |
||||
($setup.result) |
||||
? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_3, [ |
||||
_cache[4] || (_cache[4] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, "Test Results:", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_4, [ |
||||
_cache[1] || (_cache[1] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", { class: "label" }, "Download:", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_5, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.result.download) + " Mbps", 1 /* TEXT */) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_6, [ |
||||
_cache[2] || (_cache[2] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", { class: "label" }, "Upload:", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_7, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.result.upload) + " Mbps", 1 /* TEXT */) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_8, [ |
||||
_cache[3] || (_cache[3] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", { class: "label" }, "Ping:", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_9, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.result.ping) + " ms", 1 /* TEXT */) |
||||
]) |
||||
])) |
||||
: (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true) |
||||
])) |
||||
} |
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css": |
||||
/*!************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ |
||||
!*** ./node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css ***! |
||||
\************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ |
||||
/***/ ((module, __unused_webpack_exports, __webpack_require__) => { |
||||
|
||||
// style-loader: Adds some css to the DOM by adding a <style> tag
|
||||
|
||||
// load the styles
|
||||
var content = __webpack_require__(/*! !!../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css */ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css"); |
||||
if(content.__esModule) content = content.default; |
||||
if(typeof content === 'string') content = [[module.id, content, '']]; |
||||
if(content.locals) module.exports = content.locals; |
||||
// add the styles to the DOM
|
||||
var add = (__webpack_require__(/*! !../../../node_modules/vue-style-loader/lib/addStylesClient.js */ "./node_modules/vue-style-loader/lib/addStylesClient.js")["default"]) |
||||
var update = add("220dc05d", content, false, {"sourceMap":false,"shadowMode":false}); |
||||
// Hot Module Replacement
|
||||
if(true) { |
||||
// When the styles change, update the <style> tags
|
||||
if(!content.locals) { |
||||
module.hot.accept(/*! !!../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css */ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css", function() { |
||||
var newContent = __webpack_require__(/*! !!../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css */ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css"); |
||||
if(newContent.__esModule) newContent = newContent.default; |
||||
if(typeof newContent === 'string') newContent = [[module.id, newContent, '']]; |
||||
update(newContent); |
||||
}); |
||||
} |
||||
// When the module is disposed, remove the <style> tags
|
||||
module.hot.dispose(function() { update(); }); |
||||
} |
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./src/renderer/components/SpeedTest.vue": |
||||
/*!***********************************************!*\ |
||||
!*** ./src/renderer/components/SpeedTest.vue ***! |
||||
\***********************************************/ |
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var _SpeedTest_vue_vue_type_template_id_373f173a_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SpeedTest.vue?vue&type=template&id=373f173a&scoped=true */ "./src/renderer/components/SpeedTest.vue?vue&type=template&id=373f173a&scoped=true"); |
||||
/* harmony import */ var _SpeedTest_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./SpeedTest.vue?vue&type=script&lang=js */ "./src/renderer/components/SpeedTest.vue?vue&type=script&lang=js"); |
||||
/* harmony import */ var _SpeedTest_vue_vue_type_style_index_0_id_373f173a_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css */ "./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css"); |
||||
/* harmony import */ var _node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../node_modules/vue-loader/dist/exportHelper.js */ "./node_modules/vue-loader/dist/exportHelper.js"); |
||||
|
||||
|
||||
|
||||
|
||||
; |
||||
|
||||
|
||||
const __exports__ = /*#__PURE__*/(0,_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__["default"])(_SpeedTest_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__["default"], [['render',_SpeedTest_vue_vue_type_template_id_373f173a_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render],['__scopeId',"data-v-373f173a"],['__file',"src/renderer/components/SpeedTest.vue"]]) |
||||
/* hot reload */ |
||||
if (true) { |
||||
__exports__.__hmrId = "373f173a" |
||||
const api = __VUE_HMR_RUNTIME__ |
||||
module.hot.accept() |
||||
if (!api.createRecord('373f173a', __exports__)) { |
||||
api.reload('373f173a', __exports__) |
||||
} |
||||
|
||||
module.hot.accept(/*! ./SpeedTest.vue?vue&type=template&id=373f173a&scoped=true */ "./src/renderer/components/SpeedTest.vue?vue&type=template&id=373f173a&scoped=true", __WEBPACK_OUTDATED_DEPENDENCIES__ => { /* harmony import */ _SpeedTest_vue_vue_type_template_id_373f173a_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SpeedTest.vue?vue&type=template&id=373f173a&scoped=true */ "./src/renderer/components/SpeedTest.vue?vue&type=template&id=373f173a&scoped=true"); |
||||
return (() => { |
||||
api.rerender('373f173a', _SpeedTest_vue_vue_type_template_id_373f173a_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render) |
||||
})(__WEBPACK_OUTDATED_DEPENDENCIES__); }) |
||||
|
||||
} |
||||
|
||||
|
||||
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (__exports__); |
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./src/renderer/components/SpeedTest.vue?vue&type=script&lang=js": |
||||
/*!***********************************************************************!*\ |
||||
!*** ./src/renderer/components/SpeedTest.vue?vue&type=script&lang=js ***! |
||||
\***********************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ "default": () => (/* reexport safe */ _node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__["default"]) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var _node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./SpeedTest.vue?vue&type=script&lang=js */ "./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=script&lang=js"); |
||||
|
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css": |
||||
/*!*******************************************************************************************************!*\ |
||||
!*** ./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css ***! |
||||
\*******************************************************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony import */ var _node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_style_index_0_id_373f173a_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css */ "./node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=style&index=0&id=373f173a&scoped=true&lang=css"); |
||||
/* harmony import */ var _node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_style_index_0_id_373f173a_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_style_index_0_id_373f173a_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__); |
||||
/* harmony reexport (unknown) */ var __WEBPACK_REEXPORT_OBJECT__ = {}; |
||||
/* harmony reexport (unknown) */ for(const __WEBPACK_IMPORT_KEY__ in _node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_style_index_0_id_373f173a_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__) if(__WEBPACK_IMPORT_KEY__ !== "default") __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = () => _node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_style_index_0_id_373f173a_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__[__WEBPACK_IMPORT_KEY__] |
||||
/* harmony reexport (unknown) */ __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__); |
||||
|
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./src/renderer/components/SpeedTest.vue?vue&type=template&id=373f173a&scoped=true": |
||||
/*!*****************************************************************************************!*\ |
||||
!*** ./src/renderer/components/SpeedTest.vue?vue&type=template&id=373f173a&scoped=true ***! |
||||
\*****************************************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ render: () => (/* reexport safe */ _node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_template_id_373f173a_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var _node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_SpeedTest_vue_vue_type_template_id_373f173a_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./SpeedTest.vue?vue&type=template&id=373f173a&scoped=true */ "./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/components/SpeedTest.vue?vue&type=template&id=373f173a&scoped=true"); |
||||
|
||||
|
||||
/***/ }) |
||||
|
||||
}]); |
@ -1,797 +0,0 @@
@@ -1,797 +0,0 @@
|
||||
(globalThis["webpackChunkGoFaster"] = globalThis["webpackChunkGoFaster"] || []).push([["src_renderer_views_Settings_vue"],{ |
||||
|
||||
/***/ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css": |
||||
/*!************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ |
||||
!*** ./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css ***! |
||||
\************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ |
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ "./node_modules/css-loader/dist/runtime/noSourceMaps.js"); |
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); |
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ "./node_modules/css-loader/dist/runtime/api.js"); |
||||
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); |
||||
// Imports
|
||||
|
||||
|
||||
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); |
||||
// Module
|
||||
___CSS_LOADER_EXPORT___.push([module.id, ` |
||||
.settings[data-v-a5c10072] { |
||||
padding: 20px; |
||||
/* 移除强制高度和滚动条设置,让内容自然流动 */ |
||||
} |
||||
.page-header[data-v-a5c10072] { |
||||
margin-bottom: 30px; |
||||
} |
||||
.page-header h2[data-v-a5c10072] { |
||||
margin: 0; |
||||
color: var(--text-primary); |
||||
font-size: 24px; |
||||
} |
||||
.settings-content[data-v-a5c10072] { |
||||
max-width: 800px; |
||||
} |
||||
.settings-section[data-v-a5c10072] { |
||||
background: var(--card-bg); |
||||
border-radius: 8px; |
||||
padding: 24px; |
||||
margin-bottom: 24px; |
||||
box-shadow: 0 2px 8px var(--shadow-color); |
||||
} |
||||
.settings-section h3[data-v-a5c10072] { |
||||
margin: 0 0 20px 0; |
||||
color: var(--text-primary); |
||||
font-size: 18px; |
||||
border-bottom: 2px solid var(--border-color); |
||||
padding-bottom: 8px; |
||||
} |
||||
.setting-item[data-v-a5c10072] { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
margin-bottom: 20px; |
||||
padding: 16px 0; |
||||
border-bottom: 1px solid #f5f5f5; |
||||
} |
||||
.setting-item[data-v-a5c10072]:last-child { |
||||
border-bottom: none; |
||||
margin-bottom: 0; |
||||
} |
||||
.setting-item label[data-v-a5c10072] { |
||||
font-weight: 500; |
||||
color: var(--text-primary); |
||||
min-width: 200px; |
||||
} |
||||
.setting-item input[type="text"][data-v-a5c10072], |
||||
.setting-item input[type="number"][data-v-a5c10072], |
||||
.setting-item select[data-v-a5c10072] { |
||||
padding: 8px 12px; |
||||
border: 1px solid var(--input-border); |
||||
border-radius: 4px; |
||||
font-size: 14px; |
||||
min-width: 200px; |
||||
background-color: var(--input-bg); |
||||
color: var(--input-text); |
||||
} |
||||
.setting-item input[type="text"][data-v-a5c10072]:focus, |
||||
.setting-item input[type="number"][data-v-a5c10072]:focus, |
||||
.setting-item select[data-v-a5c10072]:focus { |
||||
outline: none; |
||||
border-color: var(--accent-color); |
||||
box-shadow: 0 0 0 2px rgba(74, 158, 255, 0.2); |
||||
} |
||||
|
||||
/* 开关样式 */ |
||||
.toggle-switch[data-v-a5c10072] { |
||||
position: relative; |
||||
display: inline-block; |
||||
} |
||||
.toggle-switch input[type="checkbox"][data-v-a5c10072] { |
||||
opacity: 0; |
||||
width: 0; |
||||
height: 0; |
||||
} |
||||
.toggle-label[data-v-a5c10072] { |
||||
display: block; |
||||
width: 50px; |
||||
height: 24px; |
||||
background: #ccc; |
||||
border-radius: 12px; |
||||
cursor: pointer; |
||||
position: relative; |
||||
transition: background-color 0.3s; |
||||
} |
||||
.toggle-label[data-v-a5c10072]:before { |
||||
content: ''; |
||||
position: absolute; |
||||
width: 20px; |
||||
height: 20px; |
||||
border-radius: 50%; |
||||
background: white; |
||||
top: 2px; |
||||
left: 2px; |
||||
transition: transform 0.3s; |
||||
} |
||||
.toggle-switch input[type="checkbox"]:checked + .toggle-label[data-v-a5c10072] { |
||||
background: #1976d2; |
||||
} |
||||
.toggle-switch input[type="checkbox"]:checked + .toggle-label[data-v-a5c10072]:before { |
||||
transform: translateX(26px); |
||||
} |
||||
|
||||
/* 设置描述文字 */ |
||||
.setting-description[data-v-a5c10072] { |
||||
font-size: 12px; |
||||
color: var(--text-secondary); |
||||
margin-top: 8px; |
||||
line-height: 1.4; |
||||
opacity: 0.8; |
||||
} |
||||
|
||||
/* 操作按钮 */ |
||||
.settings-actions[data-v-a5c10072] { |
||||
display: flex; |
||||
gap: 16px; |
||||
justify-content: flex-end; |
||||
margin-top: 30px; |
||||
} |
||||
.btn[data-v-a5c10072] { |
||||
padding: 12px 24px; |
||||
border: none; |
||||
border-radius: 6px; |
||||
cursor: pointer; |
||||
font-size: 14px; |
||||
font-weight: 500; |
||||
transition: all 0.2s; |
||||
} |
||||
.btn-primary[data-v-a5c10072] { |
||||
background: #1976d2; |
||||
color: white; |
||||
} |
||||
.btn-primary[data-v-a5c10072]:hover { |
||||
background: #1565c0; |
||||
} |
||||
.btn-secondary[data-v-a5c10072] { |
||||
background: #757575; |
||||
color: white; |
||||
} |
||||
.btn-secondary[data-v-a5c10072]:hover { |
||||
background: #616161; |
||||
} |
||||
|
||||
/* 响应式保存按钮样式 */ |
||||
.btn-disabled[data-v-a5c10072] { |
||||
background: #e0e0e0; |
||||
color: #9e9e9e; |
||||
cursor: not-allowed; |
||||
} |
||||
.btn-disabled[data-v-a5c10072]:hover { |
||||
background: #e0e0e0; |
||||
} |
||||
.btn-saving[data-v-a5c10072] { |
||||
background: #ff9800; |
||||
color: white; |
||||
cursor: not-allowed; |
||||
} |
||||
.btn-saving[data-v-a5c10072]:hover { |
||||
background: #ff9800; |
||||
} |
||||
|
||||
/* 响应式设计 */ |
||||
@media (max-width: 768px) { |
||||
.setting-item[data-v-a5c10072] { |
||||
flex-direction: column; |
||||
align-items: flex-start; |
||||
gap: 12px; |
||||
} |
||||
.setting-item label[data-v-a5c10072] { |
||||
min-width: auto; |
||||
} |
||||
.setting-item input[type="text"][data-v-a5c10072], |
||||
.setting-item input[type="number"][data-v-a5c10072], |
||||
.setting-item select[data-v-a5c10072] { |
||||
min-width: 100%; |
||||
} |
||||
.settings-actions[data-v-a5c10072] { |
||||
flex-direction: column; |
||||
} |
||||
} |
||||
`, ""]);
|
||||
// Exports
|
||||
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); |
||||
|
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=script&lang=js": |
||||
/*!****************************************************************************************************************************!*\ |
||||
!*** ./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=script&lang=js ***! |
||||
\****************************************************************************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.runtime.esm-bundler.js"); |
||||
/* harmony import */ var _utils_themeManager_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/themeManager.js */ "./src/renderer/utils/themeManager.js"); |
||||
/* harmony import */ var _components_Toast_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../components/Toast.vue */ "./src/renderer/components/Toast.vue"); |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ |
||||
name: 'Settings', |
||||
components: { |
||||
Toast: _components_Toast_vue__WEBPACK_IMPORTED_MODULE_2__["default"] |
||||
}, |
||||
setup() { |
||||
const settings = (0,vue__WEBPACK_IMPORTED_MODULE_0__.reactive)({ |
||||
// 基本设置
|
||||
appName: 'GoFaster', |
||||
language: 'zh-CN', |
||||
theme: 'light', |
||||
|
||||
// 网络设置
|
||||
apiUrl: 'http://localhost:8080', |
||||
timeout: 10, |
||||
retryCount: 3, |
||||
|
||||
// 用户设置
|
||||
keepLoginOnClose: false, |
||||
rememberPassword: false, |
||||
sessionTimeout: 30, |
||||
|
||||
// 通知设置
|
||||
desktopNotifications: true, |
||||
soundNotifications: true, |
||||
notificationInterval: 10, |
||||
|
||||
// 数据设置
|
||||
cacheSize: 100, |
||||
autoCleanCache: true, |
||||
backupFrequency: 'weekly' |
||||
}) |
||||
|
||||
// 保存原始设置用于比较
|
||||
const originalSettings = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)({}) |
||||
const hasChanges = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) |
||||
const isSaving = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) |
||||
|
||||
// Toast 相关状态
|
||||
const showToast = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) |
||||
const toastConfig = (0,vue__WEBPACK_IMPORTED_MODULE_0__.reactive)({ |
||||
type: 'success', |
||||
title: '保存成功', |
||||
content: '用户设置已成功保存', |
||||
duration: 3000 |
||||
}) |
||||
|
||||
// 计算保存按钮的样式类
|
||||
const saveButtonClass = (0,vue__WEBPACK_IMPORTED_MODULE_0__.computed)(() => { |
||||
if (isSaving.value) { |
||||
return 'btn-saving' |
||||
} else if (hasChanges.value) { |
||||
return 'btn-primary' |
||||
} else { |
||||
return 'btn-disabled' |
||||
} |
||||
}) |
||||
|
||||
// 检查设置是否有变化
|
||||
const checkChanges = () => { |
||||
hasChanges.value = JSON.stringify(settings) !== JSON.stringify(originalSettings.value) |
||||
} |
||||
|
||||
// 显示Toast提示
|
||||
const showToastMessage = (type, title, content, duration = 3000) => { |
||||
toastConfig.type = type |
||||
toastConfig.title = title |
||||
toastConfig.content = content |
||||
toastConfig.duration = duration |
||||
showToast.value = true |
||||
} |
||||
|
||||
const loadSettings = () => { |
||||
const savedSettings = localStorage.getItem('gofaster-settings') |
||||
if (savedSettings) { |
||||
Object.assign(settings, JSON.parse(savedSettings)) |
||||
} |
||||
|
||||
// 保存原始设置
|
||||
originalSettings.value = JSON.parse(JSON.stringify(settings)) |
||||
|
||||
// 同步主题管理器
|
||||
if (settings.theme) { |
||||
_utils_themeManager_js__WEBPACK_IMPORTED_MODULE_1__["default"].setTheme(settings.theme) |
||||
} |
||||
} |
||||
|
||||
const saveSettings = async () => { |
||||
if (!hasChanges.value || isSaving.value) return |
||||
|
||||
isSaving.value = true |
||||
|
||||
try { |
||||
// 模拟保存延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 1000)) |
||||
|
||||
localStorage.setItem('gofaster-settings', JSON.stringify(settings)) |
||||
|
||||
// 应用主题设置
|
||||
if (settings.theme) { |
||||
_utils_themeManager_js__WEBPACK_IMPORTED_MODULE_1__["default"].setTheme(settings.theme) |
||||
} |
||||
|
||||
// 触发自定义事件,通知其他组件设置已更新
|
||||
window.dispatchEvent(new CustomEvent('gofaster-settings-changed', { |
||||
detail: { settings: settings } |
||||
})); |
||||
|
||||
// 更新原始设置
|
||||
originalSettings.value = JSON.parse(JSON.stringify(settings)) |
||||
hasChanges.value = false |
||||
|
||||
// 显示保存成功提示
|
||||
showToastMessage('success', '保存成功', '用户设置已成功保存') |
||||
|
||||
|
||||
} catch (error) { |
||||
console.error('保存用户设置失败:', error) |
||||
// 显示保存失败提示
|
||||
showToastMessage('error', '保存失败', '保存用户设置时发生错误,请重试') |
||||
} finally { |
||||
isSaving.value = false |
||||
} |
||||
} |
||||
|
||||
// 主题切换处理
|
||||
const handleThemeChange = (newTheme) => { |
||||
settings.theme = newTheme |
||||
_utils_themeManager_js__WEBPACK_IMPORTED_MODULE_1__["default"].setTheme(newTheme) |
||||
} |
||||
|
||||
const resetSettings = () => { |
||||
if (confirm('确定要重置所有用户设置吗?此操作不可撤销。')) { |
||||
localStorage.removeItem('gofaster-settings') |
||||
location.reload() |
||||
} |
||||
} |
||||
|
||||
// 监听设置变化
|
||||
;(0,vue__WEBPACK_IMPORTED_MODULE_0__.watch)(settings, () => { |
||||
checkChanges() |
||||
}, { deep: true }) |
||||
|
||||
;(0,vue__WEBPACK_IMPORTED_MODULE_0__.onMounted)(() => { |
||||
loadSettings() |
||||
}) |
||||
|
||||
return { |
||||
settings, |
||||
hasChanges, |
||||
isSaving, |
||||
saveButtonClass, |
||||
showToast, |
||||
toastConfig, |
||||
saveSettings, |
||||
resetSettings, |
||||
handleThemeChange |
||||
} |
||||
} |
||||
}); |
||||
|
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=template&id=a5c10072&scoped=true": |
||||
/*!********************************************************************************************************************************************************************************************************************!*\ |
||||
!*** ./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=template&id=a5c10072&scoped=true ***! |
||||
\********************************************************************************************************************************************************************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ render: () => (/* binding */ render) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.runtime.esm-bundler.js"); |
||||
|
||||
|
||||
const _hoisted_1 = { class: "settings" } |
||||
const _hoisted_2 = { class: "settings-content" } |
||||
const _hoisted_3 = { class: "settings-section" } |
||||
const _hoisted_4 = { class: "setting-item" } |
||||
const _hoisted_5 = { class: "setting-item" } |
||||
const _hoisted_6 = { class: "setting-item" } |
||||
const _hoisted_7 = { class: "settings-section" } |
||||
const _hoisted_8 = { class: "setting-item" } |
||||
const _hoisted_9 = { class: "setting-item" } |
||||
const _hoisted_10 = { class: "settings-section" } |
||||
const _hoisted_11 = { class: "setting-item" } |
||||
const _hoisted_12 = { class: "toggle-switch" } |
||||
const _hoisted_13 = { class: "setting-item" } |
||||
const _hoisted_14 = { class: "toggle-switch" } |
||||
const _hoisted_15 = { class: "settings-section" } |
||||
const _hoisted_16 = { class: "setting-item" } |
||||
const _hoisted_17 = { class: "toggle-switch" } |
||||
const _hoisted_18 = { class: "setting-item" } |
||||
const _hoisted_19 = { class: "toggle-switch" } |
||||
const _hoisted_20 = { class: "setting-item" } |
||||
const _hoisted_21 = { class: "settings-section" } |
||||
const _hoisted_22 = { class: "setting-item" } |
||||
const _hoisted_23 = { class: "setting-item" } |
||||
const _hoisted_24 = { class: "toggle-switch" } |
||||
const _hoisted_25 = { class: "setting-item" } |
||||
const _hoisted_26 = { class: "settings-actions" } |
||||
const _hoisted_27 = ["disabled"] |
||||
const _hoisted_28 = { key: 0 } |
||||
const _hoisted_29 = { key: 1 } |
||||
const _hoisted_30 = { key: 2 } |
||||
|
||||
function render(_ctx, _cache, $props, $setup, $data, $options) { |
||||
const _component_Toast = (0,vue__WEBPACK_IMPORTED_MODULE_0__.resolveComponent)("Toast") |
||||
|
||||
return ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_1, [ |
||||
_cache[43] || (_cache[43] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", { class: "page-header" }, [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h2", null, "用户设置") |
||||
], -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_2, [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 个人偏好 "), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_3, [ |
||||
_cache[22] || (_cache[22] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, "个人偏好", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_4, [ |
||||
_cache[17] || (_cache[17] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "应用名称", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (($setup.settings.appName) = $event)), |
||||
type: "text", |
||||
placeholder: "GoFaster" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.settings.appName] |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_5, [ |
||||
_cache[19] || (_cache[19] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "语言", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("select", { |
||||
"onUpdate:modelValue": _cache[1] || (_cache[1] = $event => (($setup.settings.language) = $event)) |
||||
}, _cache[18] || (_cache[18] = [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "zh-CN" }, "简体中文", -1 /* CACHED */), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "en-US" }, "English", -1 /* CACHED */) |
||||
]), 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelSelect, $setup.settings.language] |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_6, [ |
||||
_cache[21] || (_cache[21] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "主题", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("select", { |
||||
"onUpdate:modelValue": _cache[2] || (_cache[2] = $event => (($setup.settings.theme) = $event)), |
||||
onChange: _cache[3] || (_cache[3] = $event => ($setup.handleThemeChange($setup.settings.theme))) |
||||
}, _cache[20] || (_cache[20] = [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "light" }, "浅色主题", -1 /* CACHED */), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "dark" }, "深色主题", -1 /* CACHED */), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "auto" }, "跟随系统", -1 /* CACHED */) |
||||
]), 544 /* NEED_HYDRATION, NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelSelect, $setup.settings.theme] |
||||
]) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 应用设置 "), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_7, [ |
||||
_cache[25] || (_cache[25] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, "应用设置", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_8, [ |
||||
_cache[23] || (_cache[23] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "请求超时时间 (秒)", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[4] || (_cache[4] = $event => (($setup.settings.timeout) = $event)), |
||||
type: "number", |
||||
min: "5", |
||||
max: "60" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.settings.timeout] |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_9, [ |
||||
_cache[24] || (_cache[24] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "自动重试次数", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[5] || (_cache[5] = $event => (($setup.settings.retryCount) = $event)), |
||||
type: "number", |
||||
min: "0", |
||||
max: "5" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.settings.retryCount] |
||||
]) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 用户设置 "), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_10, [ |
||||
_cache[30] || (_cache[30] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, "用户设置", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_11, [ |
||||
_cache[27] || (_cache[27] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "关闭窗口不登出", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_12, [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[6] || (_cache[6] = $event => (($setup.settings.keepLoginOnClose) = $event)), |
||||
type: "checkbox", |
||||
id: "keepLoginOnClose" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelCheckbox, $setup.settings.keepLoginOnClose] |
||||
]), |
||||
_cache[26] || (_cache[26] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", { |
||||
for: "keepLoginOnClose", |
||||
class: "toggle-label" |
||||
}, null, -1 /* CACHED */)) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_13, [ |
||||
_cache[29] || (_cache[29] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "记住密码", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_14, [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[7] || (_cache[7] = $event => (($setup.settings.rememberPassword) = $event)), |
||||
type: "checkbox", |
||||
id: "rememberPassword" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelCheckbox, $setup.settings.rememberPassword] |
||||
]), |
||||
_cache[28] || (_cache[28] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", { |
||||
for: "rememberPassword", |
||||
class: "toggle-label" |
||||
}, null, -1 /* CACHED */)) |
||||
]) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 通知偏好 "), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_15, [ |
||||
_cache[36] || (_cache[36] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, "通知偏好", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_16, [ |
||||
_cache[32] || (_cache[32] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "桌面通知", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_17, [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[8] || (_cache[8] = $event => (($setup.settings.desktopNotifications) = $event)), |
||||
type: "checkbox", |
||||
id: "desktopNotifications" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelCheckbox, $setup.settings.desktopNotifications] |
||||
]), |
||||
_cache[31] || (_cache[31] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", { |
||||
for: "desktopNotifications", |
||||
class: "toggle-label" |
||||
}, null, -1 /* CACHED */)) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_18, [ |
||||
_cache[34] || (_cache[34] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "声音提醒", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_19, [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[9] || (_cache[9] = $event => (($setup.settings.soundNotifications) = $event)), |
||||
type: "checkbox", |
||||
id: "soundNotifications" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelCheckbox, $setup.settings.soundNotifications] |
||||
]), |
||||
_cache[33] || (_cache[33] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", { |
||||
for: "soundNotifications", |
||||
class: "toggle-label" |
||||
}, null, -1 /* CACHED */)) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_20, [ |
||||
_cache[35] || (_cache[35] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "消息提醒间隔 (秒)", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[10] || (_cache[10] = $event => (($setup.settings.notificationInterval) = $event)), |
||||
type: "number", |
||||
min: "5", |
||||
max: "300" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.settings.notificationInterval] |
||||
]) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 数据管理 "), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_21, [ |
||||
_cache[42] || (_cache[42] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h3", null, "数据管理", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_22, [ |
||||
_cache[37] || (_cache[37] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "数据缓存大小 (MB)", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[11] || (_cache[11] = $event => (($setup.settings.cacheSize) = $event)), |
||||
type: "number", |
||||
min: "50", |
||||
max: "1000" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.settings.cacheSize] |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_23, [ |
||||
_cache[39] || (_cache[39] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "自动清理缓存", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_24, [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("input", { |
||||
"onUpdate:modelValue": _cache[12] || (_cache[12] = $event => (($setup.settings.autoCleanCache) = $event)), |
||||
type: "checkbox", |
||||
id: "autoCleanCache" |
||||
}, null, 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelCheckbox, $setup.settings.autoCleanCache] |
||||
]), |
||||
_cache[38] || (_cache[38] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", { |
||||
for: "autoCleanCache", |
||||
class: "toggle-label" |
||||
}, null, -1 /* CACHED */)) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_25, [ |
||||
_cache[41] || (_cache[41] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("label", null, "数据备份频率", -1 /* CACHED */)), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("select", { |
||||
"onUpdate:modelValue": _cache[13] || (_cache[13] = $event => (($setup.settings.backupFrequency) = $event)) |
||||
}, _cache[40] || (_cache[40] = [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "daily" }, "每日", -1 /* CACHED */), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "weekly" }, "每周", -1 /* CACHED */), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "monthly" }, "每月", -1 /* CACHED */), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("option", { value: "never" }, "从不", -1 /* CACHED */) |
||||
]), 512 /* NEED_PATCH */), [ |
||||
[vue__WEBPACK_IMPORTED_MODULE_0__.vModelSelect, $setup.settings.backupFrequency] |
||||
]) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" 操作按钮 "), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_26, [ |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { |
||||
class: "btn btn-secondary", |
||||
onClick: _cache[14] || (_cache[14] = (...args) => ($setup.resetSettings && $setup.resetSettings(...args))) |
||||
}, " 重置所有设置 "), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("button", { |
||||
class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(["btn", $setup.saveButtonClass]), |
||||
onClick: _cache[15] || (_cache[15] = (...args) => ($setup.saveSettings && $setup.saveSettings(...args))), |
||||
disabled: !$setup.hasChanges || $setup.isSaving |
||||
}, [ |
||||
($setup.isSaving) |
||||
? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("span", _hoisted_28, "保存中...")) |
||||
: ($setup.hasChanges) |
||||
? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("span", _hoisted_29, "保存更改")) |
||||
: ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("span", _hoisted_30, "已保存")) |
||||
], 10 /* CLASS, PROPS */, _hoisted_27) |
||||
]) |
||||
]), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(" Toast 消息提示 "), |
||||
(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_Toast, { |
||||
visible: $setup.showToast, |
||||
"onUpdate:visible": _cache[16] || (_cache[16] = $event => (($setup.showToast) = $event)), |
||||
type: $setup.toastConfig.type, |
||||
title: $setup.toastConfig.title, |
||||
content: $setup.toastConfig.content, |
||||
duration: $setup.toastConfig.duration |
||||
}, null, 8 /* PROPS */, ["visible", "type", "title", "content", "duration"]) |
||||
])) |
||||
} |
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css": |
||||
/*!******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ |
||||
!*** ./node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css ***! |
||||
\******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ |
||||
/***/ ((module, __unused_webpack_exports, __webpack_require__) => { |
||||
|
||||
// style-loader: Adds some css to the DOM by adding a <style> tag
|
||||
|
||||
// load the styles
|
||||
var content = __webpack_require__(/*! !!../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css */ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css"); |
||||
if(content.__esModule) content = content.default; |
||||
if(typeof content === 'string') content = [[module.id, content, '']]; |
||||
if(content.locals) module.exports = content.locals; |
||||
// add the styles to the DOM
|
||||
var add = (__webpack_require__(/*! !../../../node_modules/vue-style-loader/lib/addStylesClient.js */ "./node_modules/vue-style-loader/lib/addStylesClient.js")["default"]) |
||||
var update = add("57cdd173", content, false, {"sourceMap":false,"shadowMode":false}); |
||||
// Hot Module Replacement
|
||||
if(true) { |
||||
// When the styles change, update the <style> tags
|
||||
if(!content.locals) { |
||||
module.hot.accept(/*! !!../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css */ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css", function() { |
||||
var newContent = __webpack_require__(/*! !!../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css */ "./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css"); |
||||
if(newContent.__esModule) newContent = newContent.default; |
||||
if(typeof newContent === 'string') newContent = [[module.id, newContent, '']]; |
||||
update(newContent); |
||||
}); |
||||
} |
||||
// When the module is disposed, remove the <style> tags
|
||||
module.hot.dispose(function() { update(); }); |
||||
} |
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./src/renderer/views/Settings.vue": |
||||
/*!*****************************************!*\ |
||||
!*** ./src/renderer/views/Settings.vue ***! |
||||
\*****************************************/ |
||||
/***/ ((module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var _Settings_vue_vue_type_template_id_a5c10072_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Settings.vue?vue&type=template&id=a5c10072&scoped=true */ "./src/renderer/views/Settings.vue?vue&type=template&id=a5c10072&scoped=true"); |
||||
/* harmony import */ var _Settings_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Settings.vue?vue&type=script&lang=js */ "./src/renderer/views/Settings.vue?vue&type=script&lang=js"); |
||||
/* harmony import */ var _Settings_vue_vue_type_style_index_0_id_a5c10072_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css */ "./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css"); |
||||
/* harmony import */ var _node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../node_modules/vue-loader/dist/exportHelper.js */ "./node_modules/vue-loader/dist/exportHelper.js"); |
||||
|
||||
|
||||
|
||||
|
||||
; |
||||
|
||||
|
||||
const __exports__ = /*#__PURE__*/(0,_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__["default"])(_Settings_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__["default"], [['render',_Settings_vue_vue_type_template_id_a5c10072_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render],['__scopeId',"data-v-a5c10072"],['__file',"src/renderer/views/Settings.vue"]]) |
||||
/* hot reload */ |
||||
if (true) { |
||||
__exports__.__hmrId = "a5c10072" |
||||
const api = __VUE_HMR_RUNTIME__ |
||||
module.hot.accept() |
||||
if (!api.createRecord('a5c10072', __exports__)) { |
||||
api.reload('a5c10072', __exports__) |
||||
} |
||||
|
||||
module.hot.accept(/*! ./Settings.vue?vue&type=template&id=a5c10072&scoped=true */ "./src/renderer/views/Settings.vue?vue&type=template&id=a5c10072&scoped=true", __WEBPACK_OUTDATED_DEPENDENCIES__ => { /* harmony import */ _Settings_vue_vue_type_template_id_a5c10072_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Settings.vue?vue&type=template&id=a5c10072&scoped=true */ "./src/renderer/views/Settings.vue?vue&type=template&id=a5c10072&scoped=true"); |
||||
return (() => { |
||||
api.rerender('a5c10072', _Settings_vue_vue_type_template_id_a5c10072_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render) |
||||
})(__WEBPACK_OUTDATED_DEPENDENCIES__); }) |
||||
|
||||
} |
||||
|
||||
|
||||
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (__exports__); |
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./src/renderer/views/Settings.vue?vue&type=script&lang=js": |
||||
/*!*****************************************************************!*\ |
||||
!*** ./src/renderer/views/Settings.vue?vue&type=script&lang=js ***! |
||||
\*****************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ "default": () => (/* reexport safe */ _node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__["default"]) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var _node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Settings.vue?vue&type=script&lang=js */ "./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=script&lang=js"); |
||||
|
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css": |
||||
/*!*************************************************************************************************!*\ |
||||
!*** ./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css ***! |
||||
\*************************************************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony import */ var _node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_style_index_0_id_a5c10072_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!../../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../../node_modules/vue-loader/dist/stylePostLoader.js!../../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css */ "./node_modules/vue-style-loader/index.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=style&index=0&id=a5c10072&scoped=true&lang=css"); |
||||
/* harmony import */ var _node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_style_index_0_id_a5c10072_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_style_index_0_id_a5c10072_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__); |
||||
/* harmony reexport (unknown) */ var __WEBPACK_REEXPORT_OBJECT__ = {}; |
||||
/* harmony reexport (unknown) */ for(const __WEBPACK_IMPORT_KEY__ in _node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_style_index_0_id_a5c10072_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__) if(__WEBPACK_IMPORT_KEY__ !== "default") __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = () => _node_modules_vue_style_loader_index_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_style_index_0_id_a5c10072_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__[__WEBPACK_IMPORT_KEY__] |
||||
/* harmony reexport (unknown) */ __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__); |
||||
|
||||
|
||||
/***/ }), |
||||
|
||||
/***/ "./src/renderer/views/Settings.vue?vue&type=template&id=a5c10072&scoped=true": |
||||
/*!***********************************************************************************!*\ |
||||
!*** ./src/renderer/views/Settings.vue?vue&type=template&id=a5c10072&scoped=true ***! |
||||
\***********************************************************************************/ |
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
||||
|
||||
"use strict"; |
||||
__webpack_require__.r(__webpack_exports__); |
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, { |
||||
/* harmony export */ render: () => (/* reexport safe */ _node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_template_id_a5c10072_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render) |
||||
/* harmony export */ }); |
||||
/* harmony import */ var _node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_Settings_vue_vue_type_template_id_a5c10072_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!../../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./Settings.vue?vue&type=template&id=a5c10072&scoped=true */ "./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/renderer/views/Settings.vue?vue&type=template&id=a5c10072&scoped=true"); |
||||
|
||||
|
||||
/***/ }) |
||||
|
||||
}]); |
@ -0,0 +1,145 @@
@@ -0,0 +1,145 @@
|
||||
# GoFaster 模块化重构完成总结 |
||||
|
||||
## 重构目标 |
||||
将 GoFaster 项目从传统的目录结构重构为模块化架构,提高代码的可维护性和扩展性。 |
||||
|
||||
## 重构完成情况 |
||||
|
||||
### ✅ 已完成的工作 |
||||
|
||||
1. **创建模块化目录结构** |
||||
- `modules/core/` - 核心模块 |
||||
- `modules/user-management/` - 用户管理模块 |
||||
- `modules/system-settings/` - 系统设置模块 |
||||
- `modules/business-features/` - 业务功能模块 |
||||
|
||||
2. **文件迁移完成** |
||||
- 所有组件文件已迁移到对应模块 |
||||
- 所有视图文件已迁移到对应模块 |
||||
- 所有服务文件已迁移到对应模块 |
||||
- 所有工具文件已迁移到对应模块 |
||||
|
||||
3. **创建模块入口文件** |
||||
- 每个模块都有 `index.js` 入口文件 |
||||
- 创建了全局 `modules/index.js` 统一导出 |
||||
- 创建了模块配置文件 `modules/config.js` |
||||
- 创建了模块管理器 `modules/ModuleManager.js` |
||||
|
||||
4. **更新导入路径** |
||||
- 所有 Vue 文件的导入路径已更新 |
||||
- 所有 JavaScript 文件的导入路径已更新 |
||||
- 路由配置已更新为模块化导入 |
||||
|
||||
5. **删除原始文件** |
||||
- 原始 `components/` 目录已删除 |
||||
- 原始 `views/` 目录已删除 |
||||
- 原始 `services/` 目录已删除 |
||||
- 原始 `utils/` 目录已删除 |
||||
|
||||
### 📂 新的目录结构 |
||||
|
||||
``` |
||||
app/src/renderer/ |
||||
├── modules/ |
||||
│ ├── core/ # 核心模块 |
||||
│ │ ├── components/ # 核心组件 |
||||
│ │ ├── services/ # 核心服务 |
||||
│ │ ├── store/ # 核心状态管理 |
||||
│ │ ├── utils/ # 核心工具 |
||||
│ │ ├── views/ # 核心页面 |
||||
│ │ └── index.js # 模块入口 |
||||
│ ├── user-management/ # 用户管理模块 |
||||
│ │ ├── components/ # 用户管理组件 |
||||
│ │ ├── services/ # 用户管理服务 |
||||
│ │ ├── store/ # 用户管理状态 |
||||
│ │ ├── views/ # 用户管理页面 |
||||
│ │ └── index.js # 模块入口 |
||||
│ ├── system-settings/ # 系统设置模块 |
||||
│ │ ├── store/ # 设置状态管理 |
||||
│ │ ├── views/ # 设置页面 |
||||
│ │ └── index.js # 模块入口 |
||||
│ ├── business-features/ # 业务功能模块 |
||||
│ │ ├── components/ # 业务组件 |
||||
│ │ ├── services/ # 业务服务 |
||||
│ │ ├── views/ # 业务页面 |
||||
│ │ └── index.js # 模块入口 |
||||
│ ├── index.js # 全局模块入口 |
||||
│ ├── config.js # 模块配置 |
||||
│ ├── ModuleManager.js # 模块管理器 |
||||
│ ├── README.md # 模块化文档 |
||||
│ └── example-usage.js # 使用示例 |
||||
├── assets/ # 静态资源 (保留) |
||||
├── router/ # 路由配置 (保留) |
||||
├── store/ # 全局状态管理 (保留) |
||||
├── App.vue # 根组件 |
||||
└── main.js # 入口文件 |
||||
``` |
||||
|
||||
### 🔧 模块功能说明 |
||||
|
||||
1. **核心模块 (core)** |
||||
- MainLayout: 主布局组件 |
||||
- Toast: 通知组件 |
||||
- StatusBar: 状态栏组件 |
||||
- themeManager: 主题管理 |
||||
- dbService: 数据库服务 |
||||
- ipUtils: IP工具 |
||||
|
||||
2. **用户管理模块 (user-management)** |
||||
- LoginModal: 登录模态框 |
||||
- PasswordChangeModal: 密码修改模态框 |
||||
- UserProfile: 用户资料组件 |
||||
- userService: 用户服务 |
||||
- 用户管理和个人资料页面 |
||||
|
||||
3. **系统设置模块 (system-settings)** |
||||
- Settings: 设置页面 |
||||
- settingsStore: 设置状态管理 |
||||
|
||||
4. **业务功能模块 (business-features)** |
||||
- SpeedTest: 速度测试组件 |
||||
- History: 历史记录页面 |
||||
- speedTestService: 速度测试服务 |
||||
- historyService: 历史记录服务 |
||||
|
||||
### 🎯 重构优势 |
||||
|
||||
1. **模块化管理**: 功能模块清晰分离,便于维护 |
||||
2. **可扩展性**: 新功能可以独立模块形式添加 |
||||
3. **代码复用**: 模块间可以方便地共享组件和服务 |
||||
4. **团队协作**: 不同团队成员可以专注于不同模块 |
||||
5. **按需加载**: 支持模块的按需加载,提高性能 |
||||
|
||||
### 🔄 使用方式 |
||||
|
||||
```javascript |
||||
// 从模块导入组件 |
||||
import { MainLayout, Toast, themeManager } from '@/modules/core' |
||||
import { userService, LoginModal } from '@/modules/user-management' |
||||
import { Settings } from '@/modules/system-settings' |
||||
import { SpeedTest, History } from '@/modules/business-features' |
||||
|
||||
// 模块管理器使用 |
||||
import { ModuleManager } from '@/modules/ModuleManager' |
||||
const moduleManager = new ModuleManager() |
||||
``` |
||||
|
||||
### ✅ 验证检查 |
||||
|
||||
- [x] 所有文件已迁移到模块目录 |
||||
- [x] 所有导入路径已更新 |
||||
- [x] 原始目录已清理 |
||||
- [x] 模块入口文件已创建 |
||||
- [x] 路由配置已更新 |
||||
- [x] 应用入口文件已更新 |
||||
|
||||
## 下一步工作 |
||||
|
||||
1. **测试应用功能**: 确认所有功能正常工作 |
||||
2. **性能优化**: 实现模块的按需加载 |
||||
3. **文档完善**: 完善模块开发文档 |
||||
4. **代码审查**: 进行代码质量检查 |
||||
|
||||
## 重构日期 |
||||
2024年12月19日 |
||||
|
@ -1,3 +0,0 @@
@@ -1,3 +0,0 @@
|
||||
|
||||
|
||||
|
@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
|
||||
// 模块管理器
|
||||
import { MODULE_CONFIG } from './config.js' |
||||
|
||||
class ModuleManager { |
||||
constructor() { |
||||
this.modules = new Map() |
||||
this.loadedModules = new Set() |
||||
this.initializedModules = new Set() |
||||
} |
||||
|
||||
// 注册模块
|
||||
registerModule(moduleName, moduleInstance) { |
||||
if (this.modules.has(moduleName)) { |
||||
console.warn(`模块 ${moduleName} 已经注册`) |
||||
return false |
||||
} |
||||
|
||||
this.modules.set(moduleName, moduleInstance) |
||||
console.log(`模块 ${moduleName} 注册成功`) |
||||
return true |
||||
} |
||||
|
||||
// 获取模块
|
||||
getModule(moduleName) { |
||||
return this.modules.get(moduleName) |
||||
} |
||||
|
||||
// 加载模块
|
||||
async loadModule(moduleName) { |
||||
if (this.loadedModules.has(moduleName)) { |
||||
return true |
||||
} |
||||
|
||||
const config = MODULE_CONFIG[moduleName] |
||||
if (!config) { |
||||
console.error(`模块 ${moduleName} 配置不存在`) |
||||
return false |
||||
} |
||||
|
||||
// 检查依赖
|
||||
if (!this.checkDependencies(moduleName)) { |
||||
console.error(`模块 ${moduleName} 依赖检查失败`) |
||||
return false |
||||
} |
||||
|
||||
try { |
||||
// 这里可以添加模块加载逻辑
|
||||
// 例如:动态导入、异步加载等
|
||||
this.loadedModules.add(moduleName) |
||||
console.log(`模块 ${moduleName} 加载成功`) |
||||
return true |
||||
} catch (error) { |
||||
console.error(`模块 ${moduleName} 加载失败:`, error) |
||||
return false |
||||
} |
||||
} |
||||
|
||||
// 初始化模块
|
||||
async initializeModule(moduleName) { |
||||
if (this.initializedModules.has(moduleName)) { |
||||
return true |
||||
} |
||||
|
||||
if (!this.loadedModules.has(moduleName)) { |
||||
const loaded = await this.loadModule(moduleName) |
||||
if (!loaded) return false |
||||
} |
||||
|
||||
try { |
||||
const moduleInstance = this.getModule(moduleName) |
||||
if (moduleInstance && typeof moduleInstance.initialize === 'function') { |
||||
await moduleInstance.initialize() |
||||
} |
||||
|
||||
this.initializedModules.add(moduleName) |
||||
console.log(`模块 ${moduleName} 初始化成功`) |
||||
return true |
||||
} catch (error) { |
||||
console.error(`模块 ${moduleName} 初始化失败:`, error) |
||||
return false |
||||
} |
||||
} |
||||
|
||||
// 检查依赖
|
||||
checkDependencies(moduleName) { |
||||
const config = MODULE_CONFIG[moduleName] |
||||
if (!config) return false |
||||
|
||||
return config.dependencies.every(dep => { |
||||
return this.loadedModules.has(dep) |
||||
}) |
||||
} |
||||
|
||||
// 按优先级加载所有模块
|
||||
async loadAllModules() { |
||||
const sortedModules = Object.keys(MODULE_CONFIG).sort((a, b) => { |
||||
return MODULE_CONFIG[a].priority - MODULE_CONFIG[b].priority |
||||
}) |
||||
|
||||
for (const moduleName of sortedModules) { |
||||
await this.loadModule(moduleName) |
||||
} |
||||
} |
||||
|
||||
// 按优先级初始化所有模块
|
||||
async initializeAllModules() { |
||||
const sortedModules = Object.keys(MODULE_CONFIG).sort((a, b) => { |
||||
return MODULE_CONFIG[a].priority - MODULE_CONFIG[b].priority |
||||
}) |
||||
|
||||
for (const moduleName of sortedModules) { |
||||
await this.initializeModule(moduleName) |
||||
} |
||||
} |
||||
|
||||
// 获取模块状态
|
||||
getModuleStatus(moduleName) { |
||||
const loaded = this.loadedModules.has(moduleName) |
||||
const initialized = this.initializedModules.has(moduleName) |
||||
|
||||
if (!loaded) return 'not-loaded' |
||||
if (!initialized) return 'loaded' |
||||
return 'initialized' |
||||
} |
||||
|
||||
// 获取所有模块状态
|
||||
getAllModuleStatuses() { |
||||
const statuses = {} |
||||
for (const moduleName of Object.keys(MODULE_CONFIG)) { |
||||
statuses[moduleName] = this.getModuleStatus(moduleName) |
||||
} |
||||
return statuses |
||||
} |
||||
} |
||||
|
||||
// 创建单例实例
|
||||
const moduleManager = new ModuleManager() |
||||
|
||||
export default moduleManager |
||||
|
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
# GoFaster 模块化架构 |
||||
|
||||
## 概述 |
||||
|
||||
本项目已重构为模块化架构,将原有功能按业务领域划分为不同的模块,提高代码的可维护性和可扩展性。 |
||||
|
||||
## 模块结构 |
||||
|
||||
``` |
||||
modules/ |
||||
├── core/ # 核心模块 |
||||
│ ├── components/ # 核心组件 |
||||
│ ├── services/ # 核心服务 |
||||
│ ├── utils/ # 核心工具 |
||||
│ └── store/ # 核心状态管理 |
||||
├── user-management/ # 用户管理模块 |
||||
│ ├── components/ # 用户管理组件 |
||||
│ ├── services/ # 用户管理服务 |
||||
│ ├── views/ # 用户管理页面 |
||||
│ └── store/ # 用户管理状态 |
||||
├── system-settings/ # 系统设置模块 |
||||
│ ├── components/ # 系统设置组件 |
||||
│ ├── views/ # 系统设置页面 |
||||
│ └── store/ # 系统设置状态 |
||||
├── business-features/ # 业务功能模块 |
||||
│ ├── components/ # 业务功能组件 |
||||
│ ├── services/ # 业务功能服务 |
||||
│ └── views/ # 业务功能页面 |
||||
├── config.js # 模块配置 |
||||
├── ModuleManager.js # 模块管理器 |
||||
└── index.js # 主模块入口 |
||||
``` |
||||
|
||||
## 模块说明 |
||||
|
||||
### 1. 核心模块 (Core) |
||||
- **功能**: 提供应用的基础架构和核心功能 |
||||
- **包含**: 主题管理、数据库服务、核心组件等 |
||||
- **依赖**: 无 |
||||
- **优先级**: 1 |
||||
|
||||
### 2. 用户管理模块 (User Management) |
||||
- **功能**: 处理用户认证、用户信息管理、权限控制等 |
||||
- **包含**: 登录、注册、用户资料、权限管理等 |
||||
- **依赖**: 核心模块 |
||||
- **优先级**: 2 |
||||
|
||||
### 3. 系统设置模块 (System Settings) |
||||
- **功能**: 管理系统配置、用户偏好设置等 |
||||
- **包含**: 应用设置、主题设置、用户偏好等 |
||||
- **依赖**: 核心模块 |
||||
- **优先级**: 3 |
||||
|
||||
### 4. 业务功能模块 (Business Features) |
||||
- **功能**: 实现具体的业务功能 |
||||
- **包含**: 速度测试、历史记录等 |
||||
- **依赖**: 核心模块、用户管理模块 |
||||
- **优先级**: 4 |
||||
|
||||
## 使用方法 |
||||
|
||||
### 导入模块 |
||||
```javascript |
||||
// 导入特定模块 |
||||
import { userService, LoginModal } from '@/modules/user-management' |
||||
|
||||
// 导入核心功能 |
||||
import { themeManager, Toast } from '@/modules/core' |
||||
|
||||
// 导入所有模块 |
||||
import { registerModules } from '@/modules' |
||||
``` |
||||
|
||||
### 模块注册 |
||||
```javascript |
||||
import { registerModules } from '@/modules' |
||||
|
||||
// 在应用启动时注册所有模块 |
||||
registerModules(app) |
||||
``` |
||||
|
||||
### 模块管理 |
||||
```javascript |
||||
import moduleManager from '@/modules/ModuleManager' |
||||
|
||||
// 检查模块状态 |
||||
const status = moduleManager.getModuleStatus('user-management') |
||||
|
||||
// 手动加载模块 |
||||
await moduleManager.loadModule('user-management') |
||||
``` |
||||
|
||||
## 扩展新模块 |
||||
|
||||
### 1. 创建模块目录 |
||||
``` |
||||
modules/ |
||||
└── new-module/ |
||||
├── components/ |
||||
├── services/ |
||||
├── views/ |
||||
├── store/ |
||||
└── index.js |
||||
``` |
||||
|
||||
### 2. 创建模块入口文件 |
||||
```javascript |
||||
// modules/new-module/index.js |
||||
export { default as NewComponent } from './components/NewComponent.vue' |
||||
export { default as newService } from './services/newService.js' |
||||
``` |
||||
|
||||
### 3. 更新配置文件 |
||||
```javascript |
||||
// modules/config.js |
||||
export const MODULE_CONFIG = { |
||||
// ... 其他模块 |
||||
'new-module': { |
||||
name: 'New Module', |
||||
description: '新功能模块', |
||||
version: '1.0.0', |
||||
dependencies: ['core'], |
||||
priority: 5 |
||||
} |
||||
} |
||||
``` |
||||
|
||||
### 4. 更新主模块入口 |
||||
```javascript |
||||
// modules/index.js |
||||
export * from './new-module/index.js' |
||||
``` |
||||
|
||||
## 最佳实践 |
||||
|
||||
1. **模块独立性**: 每个模块应该尽可能独立,减少模块间的耦合 |
||||
2. **依赖管理**: 明确声明模块依赖关系,避免循环依赖 |
||||
3. **接口设计**: 模块间通过明确的接口进行通信 |
||||
4. **状态隔离**: 每个模块管理自己的状态,避免全局状态污染 |
||||
5. **错误处理**: 模块内部处理自己的错误,向上抛出有意义的错误信息 |
||||
|
||||
## 迁移说明 |
||||
|
||||
原有的功能已按以下方式迁移: |
||||
|
||||
- **用户认证相关** → `user-management` 模块 |
||||
- **系统设置相关** → `system-settings` 模块 |
||||
- **业务功能相关** → `business-features` 模块 |
||||
- **核心功能相关** → `core` 模块 |
||||
|
||||
## 注意事项 |
||||
|
||||
1. 模块加载顺序按照依赖关系和优先级自动确定 |
||||
2. 模块初始化失败不会影响其他模块的正常运行 |
||||
3. 可以通过模块管理器监控模块状态 |
||||
4. 新增功能建议按模块化方式组织代码 |
||||
|
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
// 业务功能模块入口文件
|
||||
|
||||
// 速度测试功能
|
||||
export { default as SpeedTest } from './components/SpeedTest.vue' |
||||
|
||||
// 历史记录功能
|
||||
export { default as History } from './views/History.vue' |
||||
|
||||
// 业务服务
|
||||
export { default as speedTestService } from './services/speedTest.js' |
||||
export { default as historyService } from './services/history.js' |
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
// 历史记录服务
|
||||
class HistoryService { |
||||
constructor() { |
||||
this.testResults = [] |
||||
} |
||||
|
||||
// 加载测试结果
|
||||
async loadTestResults() { |
||||
// 从本地存储或数据库加载测试结果
|
||||
const stored = localStorage.getItem('gofaster-test-results') |
||||
if (stored) { |
||||
this.testResults = JSON.parse(stored) |
||||
} |
||||
return this.testResults |
||||
} |
||||
|
||||
// 保存测试结果
|
||||
async saveTestResult(result) { |
||||
this.testResults.push(result) |
||||
localStorage.setItem('gofaster-test-results', JSON.stringify(this.testResults)) |
||||
return result |
||||
} |
||||
|
||||
// 获取测试结果
|
||||
getTestResults() { |
||||
return this.testResults |
||||
} |
||||
|
||||
// 清除测试结果
|
||||
async clearTestResults() { |
||||
this.testResults = [] |
||||
localStorage.removeItem('gofaster-test-results') |
||||
} |
||||
|
||||
// 格式化日期
|
||||
formatDate(timestamp) { |
||||
return new Date(timestamp).toLocaleString() |
||||
} |
||||
} |
||||
|
||||
export default new HistoryService() |
||||
|
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
// 速度测试服务
|
||||
class SpeedTestService { |
||||
constructor() { |
||||
this.testResults = [] |
||||
} |
||||
|
||||
// 开始速度测试
|
||||
async startTest() { |
||||
// 模拟网络测试 (替换为真实测试逻辑)
|
||||
await new Promise(resolve => setTimeout(resolve, 2000)) |
||||
|
||||
const testResult = { |
||||
download: (Math.random() * 100).toFixed(2), |
||||
upload: (Math.random() * 50).toFixed(2), |
||||
ping: (Math.random() * 100).toFixed(2), |
||||
timestamp: new Date().toISOString() |
||||
} |
||||
|
||||
this.testResults.push(testResult) |
||||
return testResult |
||||
} |
||||
|
||||
// 获取测试结果
|
||||
getTestResults() { |
||||
return this.testResults |
||||
} |
||||
|
||||
// 清除测试结果
|
||||
clearTestResults() { |
||||
this.testResults = [] |
||||
} |
||||
} |
||||
|
||||
export default new SpeedTestService() |
||||
|
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
// 模块配置文件
|
||||
|
||||
export const MODULE_CONFIG = { |
||||
// 核心模块配置
|
||||
core: { |
||||
name: 'Core', |
||||
description: '核心功能模块', |
||||
version: '1.0.0', |
||||
dependencies: [], |
||||
priority: 1 |
||||
}, |
||||
|
||||
// 用户管理模块配置
|
||||
'user-management': { |
||||
name: 'User Management', |
||||
description: '用户管理功能模块', |
||||
version: '1.0.0', |
||||
dependencies: ['core'], |
||||
priority: 2 |
||||
}, |
||||
|
||||
// 系统设置模块配置
|
||||
'system-settings': { |
||||
name: 'System Settings', |
||||
description: '系统设置功能模块', |
||||
version: '1.0.0', |
||||
dependencies: ['core'], |
||||
priority: 3 |
||||
}, |
||||
|
||||
// 业务功能模块配置
|
||||
'business-features': { |
||||
name: 'Business Features', |
||||
description: '业务功能模块', |
||||
version: '1.0.0', |
||||
dependencies: ['core', 'user-management'], |
||||
priority: 4 |
||||
} |
||||
} |
||||
|
||||
// 获取模块配置
|
||||
export function getModuleConfig(moduleName) { |
||||
return MODULE_CONFIG[moduleName] || null |
||||
} |
||||
|
||||
// 获取所有模块配置
|
||||
export function getAllModuleConfigs() { |
||||
return MODULE_CONFIG |
||||
} |
||||
|
||||
// 检查模块依赖
|
||||
export function checkModuleDependencies(moduleName) { |
||||
const config = getModuleConfig(moduleName) |
||||
if (!config) return false |
||||
|
||||
return config.dependencies.every(dep => { |
||||
const depConfig = getModuleConfig(dep) |
||||
return depConfig && depConfig.loaded |
||||
}) |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
// 核心模块入口文件
|
||||
export { default as themeManager } from './utils/themeManager.js' |
||||
export { default as router } from '../../router/index.js' |
||||
export { default as store } from '../../store/index.js' |
||||
|
||||
// 核心组件
|
||||
export { default as MainLayout } from './components/MainLayout.vue' |
||||
export { default as Toast } from './components/Toast.vue' |
||||
export { default as StatusBar } from './components/StatusBar.vue' |
||||
|
||||
// 核心页面
|
||||
export { default as Home } from './views/Home.vue' |
||||
export { default as ConfigTest } from './views/ConfigTest.vue' |
||||
|
||||
// 核心服务
|
||||
export { default as dbService } from './services/db.js' |
||||
|
||||
// 核心工具
|
||||
export { default as ipUtils } from './utils/ipUtils.js' |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
import { createStore } from 'vuex' |
||||
import { db } from '../services/db' |
||||
|
||||
export default createStore({ |
||||
state: { |
||||
testResults: [] |
||||
}, |
||||
mutations: { |
||||
setTestResults(state, results) { |
||||
state.testResults = results |
||||
}, |
||||
addTestResult(state, result) { |
||||
state.testResults.unshift(result) |
||||
} |
||||
}, |
||||
actions: { |
||||
async loadTestResults({ commit }) { |
||||
await db.read() |
||||
commit('setTestResults', db.data.activities || []) |
||||
}, |
||||
async saveTestResult({ commit }, result) { |
||||
await db.read() |
||||
db.data.activities.unshift(result) |
||||
await db.write() |
||||
commit('addTestResult', result) |
||||
} |
||||
} |
||||
}) |
@ -0,0 +1,136 @@
@@ -0,0 +1,136 @@
|
||||
// 模块使用示例
|
||||
|
||||
// 1. 导入核心模块
|
||||
import { themeManager, Toast, dbService } from './core' |
||||
|
||||
// 2. 导入用户管理模块
|
||||
import { userService, LoginModal, UserManagement } from './user-management' |
||||
|
||||
// 3. 导入系统设置模块
|
||||
import { Settings } from './system-settings' |
||||
|
||||
// 4. 导入业务功能模块
|
||||
import { SpeedTest, History } from './business-features' |
||||
|
||||
// 5. 导入模块管理器
|
||||
import moduleManager from './ModuleManager' |
||||
|
||||
// 示例:应用启动时初始化所有模块
|
||||
export async function initializeApp() { |
||||
console.log('开始初始化应用...') |
||||
|
||||
try { |
||||
// 按优先级加载所有模块
|
||||
await moduleManager.loadAllModules() |
||||
console.log('所有模块加载完成') |
||||
|
||||
// 按优先级初始化所有模块
|
||||
await moduleManager.initializeAllModules() |
||||
console.log('所有模块初始化完成') |
||||
|
||||
// 检查模块状态
|
||||
const statuses = moduleManager.getAllModuleStatuses() |
||||
console.log('模块状态:', statuses) |
||||
|
||||
} catch (error) { |
||||
console.error('模块初始化失败:', error) |
||||
} |
||||
} |
||||
|
||||
// 示例:使用主题管理器
|
||||
export function setupTheme() { |
||||
// 设置主题
|
||||
themeManager.setTheme('dark') |
||||
|
||||
// 获取当前主题
|
||||
const currentTheme = themeManager.getCurrentTheme() |
||||
console.log('当前主题:', currentTheme) |
||||
} |
||||
|
||||
// 示例:用户认证流程
|
||||
export async function handleUserLogin(credentials) { |
||||
try { |
||||
// 使用用户服务进行登录
|
||||
const response = await userService.login(credentials) |
||||
|
||||
if (response.success) { |
||||
// 显示成功提示
|
||||
Toast.show({ |
||||
type: 'success', |
||||
title: '登录成功', |
||||
content: '欢迎回来!' |
||||
}) |
||||
|
||||
return response |
||||
} |
||||
} catch (error) { |
||||
// 显示错误提示
|
||||
Toast.show({ |
||||
type: 'error', |
||||
title: '登录失败', |
||||
content: error.message |
||||
}) |
||||
|
||||
throw error |
||||
} |
||||
} |
||||
|
||||
// 示例:数据库操作
|
||||
export async function performDatabaseOperation() { |
||||
try { |
||||
// 使用数据库服务
|
||||
const result = await dbService.query('SELECT * FROM users') |
||||
console.log('数据库查询结果:', result) |
||||
|
||||
return result |
||||
} catch (error) { |
||||
console.error('数据库操作失败:', error) |
||||
throw error |
||||
} |
||||
} |
||||
|
||||
// 示例:动态加载模块
|
||||
export async function loadModuleOnDemand(moduleName) { |
||||
try { |
||||
const loaded = await moduleManager.loadModule(moduleName) |
||||
if (loaded) { |
||||
console.log(`模块 ${moduleName} 加载成功`) |
||||
|
||||
// 初始化模块
|
||||
await moduleManager.initializeModule(moduleName) |
||||
console.log(`模块 ${moduleName} 初始化成功`) |
||||
|
||||
return true |
||||
} |
||||
} catch (error) { |
||||
console.error(`模块 ${moduleName} 加载失败:`, error) |
||||
return false |
||||
} |
||||
} |
||||
|
||||
// 示例:模块状态监控
|
||||
export function monitorModuleStatus() { |
||||
// 定期检查模块状态
|
||||
setInterval(() => { |
||||
const statuses = moduleManager.getAllModuleStatuses() |
||||
console.log('模块状态监控:', statuses) |
||||
|
||||
// 检查是否有模块异常
|
||||
Object.entries(statuses).forEach(([moduleName, status]) => { |
||||
if (status === 'error') { |
||||
console.warn(`模块 ${moduleName} 状态异常`) |
||||
} |
||||
}) |
||||
}, 30000) // 每30秒检查一次
|
||||
} |
||||
|
||||
// 导出所有示例函数
|
||||
export { |
||||
initializeApp, |
||||
setupTheme, |
||||
handleUserLogin, |
||||
performDatabaseOperation, |
||||
loadModuleOnDemand, |
||||
monitorModuleStatus |
||||
} |
||||
|
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
// 主模块入口文件 - 统一导出所有模块
|
||||
|
||||
// 核心模块
|
||||
export * from './core/index.js' |
||||
|
||||
// 用户管理模块
|
||||
export * from './user-management/index.js' |
||||
|
||||
// 系统设置模块
|
||||
export * from './system-settings/index.js' |
||||
|
||||
// 业务功能模块
|
||||
export * from './business-features/index.js' |
||||
|
||||
// 模块注册函数
|
||||
export function registerModules(app) { |
||||
console.log('注册所有模块...') |
||||
|
||||
// 这里可以添加模块初始化逻辑
|
||||
// 例如:注册全局组件、插件等
|
||||
|
||||
console.log('所有模块注册完成') |
||||
} |
||||
|
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
// 系统设置模块入口文件
|
||||
|
||||
// 系统设置页面
|
||||
export { default as Settings } from './views/Settings.vue' |
||||
|
||||
// 系统设置状态
|
||||
export { default as settingsStore } from './store/settings.js' |
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
// 系统设置状态管理
|
||||
import { reactive } from 'vue' |
||||
|
||||
const state = reactive({ |
||||
settings: { |
||||
// 主题设置
|
||||
theme: 'light', |
||||
autoTheme: true, |
||||
|
||||
// 用户设置
|
||||
keepLoginOnClose: false, |
||||
rememberPassword: false, |
||||
sessionTimeout: 30, |
||||
|
||||
// 系统设置
|
||||
language: 'zh-CN', |
||||
notifications: true, |
||||
autoUpdate: true |
||||
}, |
||||
|
||||
loading: false, |
||||
error: null, |
||||
hasChanges: false |
||||
}) |
||||
|
||||
const actions = { |
||||
// 更新设置
|
||||
updateSettings(newSettings) { |
||||
Object.assign(state.settings, newSettings) |
||||
state.hasChanges = true |
||||
}, |
||||
|
||||
// 重置设置
|
||||
resetSettings() { |
||||
// 从本地存储加载默认设置
|
||||
const stored = localStorage.getItem('gofaster-settings') |
||||
if (stored) { |
||||
try { |
||||
const parsed = JSON.parse(stored) |
||||
Object.assign(state.settings, parsed) |
||||
} catch (e) { |
||||
console.error('Failed to parse stored settings:', e) |
||||
} |
||||
} |
||||
state.hasChanges = false |
||||
}, |
||||
|
||||
// 保存设置
|
||||
async saveSettings() { |
||||
state.loading = true |
||||
try { |
||||
localStorage.setItem('gofaster-settings', JSON.stringify(state.settings)) |
||||
state.hasChanges = false |
||||
return true |
||||
} catch (e) { |
||||
state.error = e.message |
||||
return false |
||||
} finally { |
||||
state.loading = false |
||||
} |
||||
}, |
||||
|
||||
// 设置加载状态
|
||||
setLoading(loading) { |
||||
state.loading = loading |
||||
}, |
||||
|
||||
// 设置错误信息
|
||||
setError(error) { |
||||
state.error = error |
||||
}, |
||||
|
||||
// 检查是否有更改
|
||||
checkChanges() { |
||||
return state.hasChanges |
||||
} |
||||
} |
||||
|
||||
export default { |
||||
state, |
||||
actions |
||||
} |
||||
|
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
<template> |
||||
<div class="password-profile"> |
||||
<h3>密码配置</h3> |
||||
<p>密码配置功能正在开发中...</p> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
name: 'PasswordProfile', |
||||
setup() { |
||||
return {} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.password-profile { |
||||
padding: 20px; |
||||
} |
||||
</style> |
||||
|
||||
|
||||
|
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
// 用户管理模块入口文件
|
||||
export { default as userService } from './services/userService.js' |
||||
|
||||
// 用户管理组件
|
||||
export { default as LoginModal } from './components/LoginModal.vue' |
||||
export { default as PasswordProfile } from './components/PasswordProfile.vue' |
||||
|
||||
// 用户管理页面
|
||||
export { default as UserProfile } from './views/UserProfile.vue' |
||||
|
||||
// 用户管理页面
|
||||
export { default as UserManagement } from './views/UserManagement.vue' |
||||
export { default as UserProfilePage } from './views/UserProfile.vue' |
||||
|
||||
// 用户管理状态
|
||||
export { default as userStore } from './store/user.js' |
@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
|
||||
import axios from 'axios' |
||||
|
||||
// 配置axios基础URL
|
||||
import { getFinalConfig } from '../../config/app.config.js'; |
||||
import { getFinalConfig } from '../../../../config/app.config.js'; |
||||
|
||||
const getApiBaseUrl = () => getFinalConfig().apiBaseUrl; |
||||
|
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
// 用户管理状态管理
|
||||
import { reactive } from 'vue' |
||||
|
||||
const state = reactive({ |
||||
currentUser: null, |
||||
isLoggedIn: false, |
||||
token: null, |
||||
userList: [], |
||||
loading: false, |
||||
error: null |
||||
}) |
||||
|
||||
const actions = { |
||||
// 设置当前用户
|
||||
setCurrentUser(user) { |
||||
state.currentUser = user |
||||
state.isLoggedIn = !!user |
||||
if (user && user.token) { |
||||
state.token = user.token |
||||
} |
||||
}, |
||||
|
||||
// 清除当前用户
|
||||
clearCurrentUser() { |
||||
state.currentUser = null |
||||
state.isLoggedIn = false |
||||
state.token = null |
||||
}, |
||||
|
||||
// 设置用户列表
|
||||
setUserList(users) { |
||||
state.userList = users |
||||
}, |
||||
|
||||
// 设置加载状态
|
||||
setLoading(loading) { |
||||
state.loading = loading |
||||
}, |
||||
|
||||
// 设置错误信息
|
||||
setError(error) { |
||||
state.error = error |
||||
} |
||||
} |
||||
|
||||
export default { |
||||
state, |
||||
actions |
||||
} |
||||
|
@ -0,0 +1,630 @@
@@ -0,0 +1,630 @@
|
||||
<template> |
||||
<div class="user-profile"> |
||||
<div class="profile-header"> |
||||
<h1>👤 个人资料</h1> |
||||
<p class="profile-subtitle">查看和管理您的账户信息</p> |
||||
</div> |
||||
|
||||
<!-- 加载状态 --> |
||||
<div v-if="loading" class="loading-container"> |
||||
<div class="loading-spinner"></div> |
||||
<p>正在加载用户信息...</p> |
||||
</div> |
||||
|
||||
<!-- 错误状态 --> |
||||
<div v-else-if="error" class="error-container"> |
||||
<div class="error-icon">❌</div> |
||||
<h3>加载失败</h3> |
||||
<p>{{ error }}</p> |
||||
<button @click="loadUserProfile" class="retry-btn">重试</button> |
||||
</div> |
||||
|
||||
<!-- 用户信息内容 --> |
||||
<div v-else-if="userInfo" class="profile-content"> |
||||
<!-- 基本信息卡片 --> |
||||
<div class="profile-card"> |
||||
<div class="card-header"> |
||||
<h2>📋 基本信息</h2> |
||||
</div> |
||||
<div class="card-content"> |
||||
<div class="info-grid"> |
||||
<div class="info-item"> |
||||
<label>用户ID</label> |
||||
<span>{{ userInfo.id || 'N/A' }}</span> |
||||
</div> |
||||
<div class="info-item"> |
||||
<label>用户名</label> |
||||
<span>{{ userInfo.username || userInfo.name || 'N/A' }}</span> |
||||
</div> |
||||
<div class="info-item"> |
||||
<label>邮箱</label> |
||||
<span>{{ userInfo.email || 'N/A' }}</span> |
||||
</div> |
||||
<div class="info-item"> |
||||
<label>手机号</label> |
||||
<span>{{ userInfo.phone || 'N/A' }}</span> |
||||
</div> |
||||
<div class="info-item"> |
||||
<label>状态</label> |
||||
<span :class="['status-badge', getStatusClass(userInfo.status)]"> |
||||
{{ getStatusText(userInfo.status) }} |
||||
</span> |
||||
</div> |
||||
<div class="info-item"> |
||||
<label>注册时间</label> |
||||
<span>{{ formatDate(userInfo.created_at) || formatDate(userInfo.createdAt) || 'N/A' }}</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 登录信息卡片 --> |
||||
<div class="profile-card"> |
||||
<div class="card-header"> |
||||
<h2>🔐 登录信息</h2> |
||||
</div> |
||||
<div class="card-content"> |
||||
<div class="info-grid"> |
||||
<div class="info-item"> |
||||
<label>上次登录时间</label> |
||||
<span>{{ formatDate(userInfo.last_login_at) || formatDate(userInfo.lastLogin) || 'N/A' }}</span> |
||||
</div> |
||||
<div class="info-item"> |
||||
<label>上次登录IP</label> |
||||
<span>{{ userInfo.last_login_ip || userInfo.lastLoginIP || 'N/A' }}</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 角色信息卡片 --> |
||||
<div class="profile-card"> |
||||
<div class="card-header"> |
||||
<h2>👑 角色信息</h2> |
||||
</div> |
||||
<div class="card-content"> |
||||
<div v-if="userInfo.roles && userInfo.roles.length > 0" class="roles-list"> |
||||
<div v-for="role in userInfo.roles" :key="role.id" class="role-item"> |
||||
<div class="role-header"> |
||||
<span class="role-name">{{ role.name }}</span> |
||||
<span class="role-description">{{ role.description || '无描述' }}</span> |
||||
</div> |
||||
<div class="role-permissions"> |
||||
<h4>权限列表:</h4> |
||||
<div class="permissions-grid"> |
||||
<span |
||||
v-for="permission in role.permissions" |
||||
:key="permission.id" |
||||
class="permission-tag" |
||||
> |
||||
{{ permission.name }} |
||||
</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div v-else class="no-roles"> |
||||
<p>暂无角色信息</p> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 操作按钮 --> |
||||
<div class="profile-actions"> |
||||
<button @click="refreshProfile" class="action-btn refresh-btn"> |
||||
🔄 刷新信息 |
||||
</button> |
||||
<button @click="changePassword" class="action-btn password-btn"> |
||||
🔒 修改密码 |
||||
</button> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 空状态 --> |
||||
<div v-else class="empty-state"> |
||||
<div class="empty-icon">👤</div> |
||||
<h3>暂无用户信息</h3> |
||||
<p>请先登录以查看您的个人资料</p> |
||||
<button @click="goToLogin" class="login-btn">去登录</button> |
||||
</div> |
||||
|
||||
<!-- 密码修改弹窗 --> |
||||
<PasswordChangeModal |
||||
v-model:visible="showPasswordModal" |
||||
:is-force-change="isForceChange" |
||||
@close="showPasswordModal = false" |
||||
@success="onPasswordChangeSuccess" |
||||
/> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { ref, onMounted, inject } from 'vue' |
||||
import { useRouter } from 'vue-router' |
||||
import { userService } from '../services/userService.js' |
||||
import PasswordChangeModal from '../components/PasswordChangeModal.vue' |
||||
|
||||
export default { |
||||
name: 'UserProfile', |
||||
components: { |
||||
PasswordChangeModal |
||||
}, |
||||
setup() { |
||||
const router = useRouter() |
||||
|
||||
// 注入依赖 |
||||
const currentUser = inject('currentUser', null) |
||||
const isLoggedIn = inject('isLoggedIn', false) |
||||
const showLoginModal = inject('showLoginModal', null) |
||||
|
||||
// 响应式数据 |
||||
const loading = ref(false) |
||||
const error = ref(null) |
||||
const userInfo = ref(null) |
||||
|
||||
// 密码修改弹窗状态 |
||||
const showPasswordModal = ref(false) |
||||
const isForceChange = ref(false) |
||||
|
||||
// 加载用户资料 |
||||
const loadUserProfile = async () => { |
||||
if (!isLoggedIn.value) { |
||||
error.value = '请先登录' |
||||
return |
||||
} |
||||
|
||||
loading.value = true |
||||
error.value = null |
||||
|
||||
try { |
||||
const token = localStorage.getItem('token') |
||||
if (!token) { |
||||
throw new Error('未找到认证token') |
||||
} |
||||
|
||||
const response = await userService.getCurrentUser(token) |
||||
userInfo.value = response.data || response |
||||
|
||||
console.log('加载的用户信息:', userInfo.value) |
||||
} catch (err) { |
||||
console.error('加载用户资料失败:', err) |
||||
error.value = err.response?.data?.message || err.message || '加载用户资料失败' |
||||
} finally { |
||||
loading.value = false |
||||
} |
||||
} |
||||
|
||||
// 刷新资料 |
||||
const refreshProfile = () => { |
||||
loadUserProfile() |
||||
} |
||||
|
||||
|
||||
|
||||
// 修改密码 |
||||
const changePassword = () => { |
||||
isForceChange.value = false |
||||
showPasswordModal.value = true |
||||
} |
||||
|
||||
// 强制修改密码 |
||||
const forceChangePassword = () => { |
||||
isForceChange.value = true |
||||
showPasswordModal.value = true |
||||
} |
||||
|
||||
// 密码修改成功回调 |
||||
const onPasswordChangeSuccess = () => { |
||||
// 刷新用户信息 |
||||
loadUserProfile() |
||||
} |
||||
|
||||
// 去登录 |
||||
const goToLogin = () => { |
||||
if (showLoginModal) { |
||||
showLoginModal() |
||||
} else { |
||||
router.push('/') |
||||
} |
||||
} |
||||
|
||||
// 格式化日期 |
||||
const formatDate = (dateString) => { |
||||
if (!dateString) return null |
||||
try { |
||||
const date = new Date(dateString) |
||||
return date.toLocaleString('zh-CN', { |
||||
year: 'numeric', |
||||
month: '2-digit', |
||||
day: '2-digit', |
||||
hour: '2-digit', |
||||
minute: '2-digit', |
||||
second: '2-digit' |
||||
}) |
||||
} catch (err) { |
||||
return dateString |
||||
} |
||||
} |
||||
|
||||
// 获取状态文本 |
||||
const getStatusText = (status) => { |
||||
const statusMap = { |
||||
1: '正常', |
||||
0: '禁用', |
||||
2: '待验证' |
||||
} |
||||
return statusMap[status] || '未知' |
||||
} |
||||
|
||||
// 获取状态样式类 |
||||
const getStatusClass = (status) => { |
||||
const classMap = { |
||||
1: 'status-active', |
||||
0: 'status-inactive', |
||||
2: 'status-pending' |
||||
} |
||||
return classMap[status] || 'status-unknown' |
||||
} |
||||
|
||||
// 组件挂载时加载数据 |
||||
onMounted(() => { |
||||
if (isLoggedIn.value) { |
||||
loadUserProfile() |
||||
} |
||||
}) |
||||
|
||||
return { |
||||
loading, |
||||
error, |
||||
userInfo, |
||||
currentUser, |
||||
isLoggedIn, |
||||
showPasswordModal, |
||||
isForceChange, |
||||
loadUserProfile, |
||||
refreshProfile, |
||||
changePassword, |
||||
forceChangePassword, |
||||
onPasswordChangeSuccess, |
||||
goToLogin, |
||||
formatDate, |
||||
getStatusText, |
||||
getStatusClass |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.user-profile { |
||||
padding: 20px; |
||||
/* 移除强制高度和滚动条设置,让内容自然流动 */ |
||||
} |
||||
|
||||
.profile-header { |
||||
text-align: center; |
||||
margin-bottom: 30px; |
||||
} |
||||
|
||||
.profile-header h1 { |
||||
font-size: 2.5rem; |
||||
color: var(--text-primary); |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
.profile-subtitle { |
||||
font-size: 1.1rem; |
||||
color: var(--text-secondary); |
||||
margin: 0; |
||||
} |
||||
|
||||
.loading-container { |
||||
text-align: center; |
||||
padding: 60px 20px; |
||||
} |
||||
|
||||
.loading-spinner { |
||||
width: 50px; |
||||
height: 50px; |
||||
border: 4px solid #f3f3f3; |
||||
border-top: 4px solid #3498db; |
||||
border-radius: 50%; |
||||
animation: spin 1s linear infinite; |
||||
margin: 0 auto 20px; |
||||
} |
||||
|
||||
@keyframes spin { |
||||
0% { transform: rotate(0deg); } |
||||
100% { transform: rotate(360deg); } |
||||
} |
||||
|
||||
.error-container { |
||||
text-align: center; |
||||
padding: 60px 20px; |
||||
background: #fff5f5; |
||||
border-radius: 12px; |
||||
border: 1px solid #fed7d7; |
||||
} |
||||
|
||||
.error-icon { |
||||
font-size: 3rem; |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
.retry-btn { |
||||
background: #e53e3e; |
||||
color: white; |
||||
border: none; |
||||
padding: 12px 24px; |
||||
border-radius: 8px; |
||||
cursor: pointer; |
||||
font-size: 1rem; |
||||
margin-top: 20px; |
||||
} |
||||
|
||||
.retry-btn:hover { |
||||
background: #c53030; |
||||
} |
||||
|
||||
.profile-content { |
||||
max-width: 800px; |
||||
margin: 0 auto; |
||||
} |
||||
|
||||
.profile-card { |
||||
background: var(--card-bg); |
||||
border-radius: 8px; |
||||
padding: 24px; |
||||
margin-bottom: 24px; |
||||
box-shadow: 0 2px 8px var(--shadow-color); |
||||
} |
||||
|
||||
.card-header { |
||||
margin: 0 0 20px 0; |
||||
color: var(--text-primary); |
||||
font-size: 18px; |
||||
border-bottom: 2px solid var(--border-color); |
||||
padding-bottom: 8px; |
||||
} |
||||
|
||||
.card-header h2 { |
||||
margin: 0; |
||||
font-size: 18px; |
||||
color: var(--text-primary); |
||||
} |
||||
|
||||
.info-grid { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 0; |
||||
} |
||||
|
||||
.info-item { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
margin-bottom: 20px; |
||||
padding: 16px 0; |
||||
border-bottom: 1px solid #f5f5f5; |
||||
} |
||||
|
||||
.info-item:last-child { |
||||
border-bottom: none; |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
.info-item label { |
||||
font-weight: 500; |
||||
color: var(--text-primary); |
||||
min-width: 200px; |
||||
} |
||||
|
||||
.info-item span { |
||||
color: var(--text-primary); |
||||
font-size: 14px; |
||||
text-align: right; |
||||
flex: 1; |
||||
} |
||||
|
||||
.status-badge { |
||||
display: inline-block; |
||||
padding: 6px 12px; |
||||
border-radius: 20px; |
||||
font-size: 0.85rem; |
||||
font-weight: 600; |
||||
text-align: center; |
||||
min-width: 80px; |
||||
} |
||||
|
||||
.status-active { |
||||
background: #d4edda; |
||||
color: #155724; |
||||
} |
||||
|
||||
.status-inactive { |
||||
background: #f8d7da; |
||||
color: #721c24; |
||||
} |
||||
|
||||
.status-pending { |
||||
background: #fff3cd; |
||||
color: #856404; |
||||
} |
||||
|
||||
.status-unknown { |
||||
background: #e2e3e5; |
||||
color: #383d41; |
||||
} |
||||
|
||||
.roles-list { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 20px; |
||||
} |
||||
|
||||
.role-item { |
||||
background: var(--card-bg); |
||||
border-radius: 8px; |
||||
padding: 20px; |
||||
border: 1px solid var(--border-color); |
||||
margin-bottom: 16px; |
||||
} |
||||
|
||||
.role-header { |
||||
margin-bottom: 16px; |
||||
} |
||||
|
||||
.role-name { |
||||
display: block; |
||||
font-size: 1.1rem; |
||||
font-weight: 600; |
||||
color: var(--text-primary); |
||||
margin-bottom: 8px; |
||||
} |
||||
|
||||
.role-description { |
||||
color: var(--text-secondary); |
||||
font-size: 0.9rem; |
||||
} |
||||
|
||||
.role-permissions h4 { |
||||
margin: 0 0 12px 0; |
||||
color: var(--text-primary); |
||||
font-size: 1rem; |
||||
} |
||||
|
||||
.permissions-grid { |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
gap: 8px; |
||||
} |
||||
|
||||
.permission-tag { |
||||
background: var(--accent-color); |
||||
color: white; |
||||
padding: 4px 12px; |
||||
border-radius: 16px; |
||||
font-size: 0.85rem; |
||||
border: none; |
||||
} |
||||
|
||||
.no-roles { |
||||
text-align: center; |
||||
color: var(--text-secondary); |
||||
padding: 40px 20px; |
||||
} |
||||
|
||||
.profile-actions { |
||||
display: flex; |
||||
gap: 16px; |
||||
justify-content: flex-end; |
||||
margin-top: 30px; |
||||
} |
||||
|
||||
.action-btn { |
||||
padding: 12px 24px; |
||||
border: none; |
||||
border-radius: 6px; |
||||
cursor: pointer; |
||||
font-size: 14px; |
||||
font-weight: 500; |
||||
transition: all 0.2s; |
||||
} |
||||
|
||||
.refresh-btn { |
||||
background: #1976d2; |
||||
color: white; |
||||
} |
||||
|
||||
.refresh-btn:hover { |
||||
background: #1565c0; |
||||
} |
||||
|
||||
.edit-btn { |
||||
background: #f39c12; |
||||
color: white; |
||||
} |
||||
|
||||
.edit-btn:hover { |
||||
background: #e67e22; |
||||
} |
||||
|
||||
.password-btn { |
||||
background: #e74c3c; |
||||
color: white; |
||||
} |
||||
|
||||
.password-btn:hover { |
||||
background: #c0392b; |
||||
} |
||||
|
||||
.empty-state { |
||||
text-align: center; |
||||
padding: 80px 20px; |
||||
} |
||||
|
||||
.empty-icon { |
||||
font-size: 4rem; |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
.empty-state h3 { |
||||
color: var(--text-primary); |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
.empty-state p { |
||||
color: var(--text-secondary); |
||||
margin-bottom: 30px; |
||||
} |
||||
|
||||
.login-btn { |
||||
background: #1976d2; |
||||
color: white; |
||||
border: none; |
||||
padding: 12px 32px; |
||||
border-radius: 6px; |
||||
cursor: pointer; |
||||
font-size: 14px; |
||||
font-weight: 500; |
||||
} |
||||
|
||||
.login-btn:hover { |
||||
background: #1565c0; |
||||
} |
||||
|
||||
/* 响应式设计 */ |
||||
@media (max-width: 768px) { |
||||
.user-profile { |
||||
padding: 15px; |
||||
} |
||||
|
||||
.profile-header h1 { |
||||
font-size: 2rem; |
||||
} |
||||
|
||||
.info-item { |
||||
flex-direction: column; |
||||
align-items: flex-start; |
||||
gap: 12px; |
||||
} |
||||
|
||||
.info-item label { |
||||
min-width: auto; |
||||
} |
||||
|
||||
.info-item span { |
||||
text-align: left; |
||||
} |
||||
|
||||
.profile-actions { |
||||
flex-direction: column; |
||||
align-items: center; |
||||
} |
||||
|
||||
.action-btn { |
||||
width: 100%; |
||||
max-width: 300px; |
||||
} |
||||
} |
||||
</style> |
@ -1 +1 @@
@@ -1 +1 @@
|
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 |
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 |
Loading…
Reference in new issue