Compare commits

...

4 Commits

Author SHA1 Message Date
f1934ba444 优化界面 2025-09-19 15:15:20 +08:00
3cf3c9268c 修改bug 2025-09-19 14:53:16 +08:00
61764be51e 增加主页 2025-09-19 14:38:47 +08:00
1e894b7700 定义api 2025-09-19 14:34:51 +08:00
35 changed files with 2884 additions and 78 deletions

View File

@@ -4,7 +4,6 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>猪场管理系统</title>
<link rel="stylesheet" href="./src/assets/styles/main.css">
</head>
<body>
<div id="app"></div>

16
node_modules/.package-lock.json generated vendored
View File

@@ -9333,6 +9333,22 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/style-loader": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/style-loader/-/style-loader-4.0.0.tgz",
"integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==",
"dev": true,
"engines": {
"node": ">= 18.12.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^5.27.0"
}
},
"node_modules/stylehacks": {
"version": "5.1.1",
"resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz",

20
node_modules/style-loader/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

1270
node_modules/style-loader/README.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

4
node_modules/style-loader/dist/cjs.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
"use strict";
const loader = require("./index");
module.exports = loader.default;

151
node_modules/style-loader/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,151 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _path = _interopRequireDefault(require("path"));
var _utils = require("./utils");
var _options = _interopRequireDefault(require("./options.json"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// eslint-disable-next-line consistent-return
const loader = function loader(content) {
if (this._compiler && this._compiler.options && this._compiler.options.experiments && this._compiler.options.experiments.css && this._module && (this._module.type === "css" || this._module.type === "css/global" || this._module.type === "css/module" || this._module.type === "css/auto")) {
return content;
}
};
loader.pitch = function pitch(request) {
if (this._compiler && this._compiler.options && this._compiler.options.experiments && this._compiler.options.experiments.css && this._module && (this._module.type === "css" || this._module.type === "css/global" || this._module.type === "css/module" || this._module.type === "css/auto")) {
this.emitWarning(new Error('You can\'t use `experiments.css` (`experiments.futureDefaults` enable built-in CSS support by default) and `style-loader` together, please set `experiments.css` to `false` or set `{ type: "javascript/auto" }` for rules with `style-loader` in your webpack config (now `style-loader` does nothing).'));
return;
}
const options = this.getOptions(_options.default);
const injectType = options.injectType || "styleTag";
const esModule = typeof options.esModule !== "undefined" ? options.esModule : true;
const runtimeOptions = {};
if (options.attributes) {
runtimeOptions.attributes = options.attributes;
}
if (options.base) {
runtimeOptions.base = options.base;
}
const insertType = options.insert && _path.default.isAbsolute(options.insert) ? "module-path" : "selector";
switch (injectType) {
case "linkTag":
{
const hmrCode = this.hot ? (0, _utils.getLinkHmrCode)(esModule, this, request) : "";
// eslint-disable-next-line consistent-return
return `
${(0, _utils.getImportLinkAPICode)(esModule, this)}
${(0, _utils.getImportInsertBySelectorCode)(esModule, this, insertType, options)}
${(0, _utils.getImportLinkContentCode)(esModule, this, request)}
${esModule ? "" : `content = content.__esModule ? content.default : content;`}
var options = ${JSON.stringify(runtimeOptions)};
${(0, _utils.getInsertOptionCode)(insertType, options)}
var update = API(content, options);
${hmrCode}
${esModule ? "export default {}" : ""}`;
}
case "lazyStyleTag":
case "lazyAutoStyleTag":
case "lazySingletonStyleTag":
{
const isSingleton = injectType === "lazySingletonStyleTag";
const isAuto = injectType === "lazyAutoStyleTag";
const hmrCode = this.hot ? (0, _utils.getStyleHmrCode)(esModule, this, request, true) : "";
// eslint-disable-next-line consistent-return
return `
var exported = {};
${(0, _utils.getImportStyleAPICode)(esModule, this)}
${(0, _utils.getImportStyleDomAPICode)(esModule, this, isSingleton, isAuto)}
${(0, _utils.getImportInsertBySelectorCode)(esModule, this, insertType, options)}
${(0, _utils.getSetAttributesCode)(esModule, this, options)}
${(0, _utils.getImportInsertStyleElementCode)(esModule, this)}
${(0, _utils.getStyleTagTransformFnCode)(esModule, this, options, isSingleton)}
${(0, _utils.getImportStyleContentCode)(esModule, this, request)}
${isAuto ? (0, _utils.getImportIsOldIECode)(esModule, this) : ""}
${esModule ? `if (content && content.locals) {
exported.locals = content.locals;
}
` : `content = content.__esModule ? content.default : content;
exported.locals = content.locals || {};`}
var refs = 0;
var update;
var options = ${JSON.stringify(runtimeOptions)};
${(0, _utils.getStyleTagTransformFn)(options, isSingleton)};
options.setAttributes = setAttributes;
${(0, _utils.getInsertOptionCode)(insertType, options)}
options.domAPI = ${(0, _utils.getdomAPI)(isAuto)};
options.insertStyleElement = insertStyleElement;
exported.use = function(insertOptions) {
options.options = insertOptions || {};
if (!(refs++)) {
update = API(content, options);
}
return exported;
};
exported.unuse = function() {
if (refs > 0 && !--refs) {
update();
update = null;
}
};
${hmrCode}
${(0, _utils.getExportLazyStyleCode)(esModule, this, request)}
`;
}
case "styleTag":
case "autoStyleTag":
case "singletonStyleTag":
default:
{
const isSingleton = injectType === "singletonStyleTag";
const isAuto = injectType === "autoStyleTag";
const hmrCode = this.hot ? (0, _utils.getStyleHmrCode)(esModule, this, request, false) : "";
// eslint-disable-next-line consistent-return
return `
${(0, _utils.getImportStyleAPICode)(esModule, this)}
${(0, _utils.getImportStyleDomAPICode)(esModule, this, isSingleton, isAuto)}
${(0, _utils.getImportInsertBySelectorCode)(esModule, this, insertType, options)}
${(0, _utils.getSetAttributesCode)(esModule, this, options)}
${(0, _utils.getImportInsertStyleElementCode)(esModule, this)}
${(0, _utils.getStyleTagTransformFnCode)(esModule, this, options, isSingleton)}
${(0, _utils.getImportStyleContentCode)(esModule, this, request)}
${isAuto ? (0, _utils.getImportIsOldIECode)(esModule, this) : ""}
${esModule ? "" : `content = content.__esModule ? content.default : content;`}
var options = ${JSON.stringify(runtimeOptions)};
${(0, _utils.getStyleTagTransformFn)(options, isSingleton)};
options.setAttributes = setAttributes;
${(0, _utils.getInsertOptionCode)(insertType, options)}
options.domAPI = ${(0, _utils.getdomAPI)(isAuto)};
options.insertStyleElement = insertStyleElement;
var update = API(content, options);
${hmrCode}
${(0, _utils.getExportStyleCode)(esModule, this, request)}
`;
}
}
};
var _default = exports.default = loader;

45
node_modules/style-loader/dist/options.json generated vendored Normal file
View File

@@ -0,0 +1,45 @@
{
"title": "Style Loader options",
"type": "object",
"properties": {
"injectType": {
"description": "Allows to setup how styles will be injected into DOM.",
"link": "https://github.com/webpack-contrib/style-loader#injecttype",
"enum": [
"styleTag",
"singletonStyleTag",
"autoStyleTag",
"lazyStyleTag",
"lazySingletonStyleTag",
"lazyAutoStyleTag",
"linkTag"
]
},
"attributes": {
"description": "Adds custom attributes to tag.",
"link": "https://github.com/webpack-contrib/style-loader#attributes",
"type": "object"
},
"insert": {
"description": "Inserts `<style>`/`<link>` at the given position.",
"link": "https://github.com/webpack-contrib/style-loader#insert",
"type": "string"
},
"base": {
"description": "Sets module ID base for DLLPlugin.",
"link": "https://github.com/webpack-contrib/style-loader#base",
"type": "number"
},
"esModule": {
"description": "Use the ES modules syntax.",
"link": "https://github.com/webpack-contrib/css-loader#esmodule",
"type": "boolean"
},
"styleTagTransform": {
"description": "Transform tag and css when insert 'style' tag into the DOM",
"link": "https://github.com/webpack-contrib/style-loader#styleTagTransform",
"type": "string"
}
},
"additionalProperties": false
}

View File

@@ -0,0 +1,29 @@
"use strict";
module.exports = function (url, options) {
if (typeof document === "undefined") {
return function () {};
}
options = options || {};
options.attributes = typeof options.attributes === "object" ? options.attributes : {};
if (typeof options.attributes.nonce === "undefined") {
var nonce = typeof __webpack_nonce__ !== "undefined" ? __webpack_nonce__ : null;
if (nonce) {
options.attributes.nonce = nonce;
}
}
var linkElement = document.createElement("link");
linkElement.rel = "stylesheet";
linkElement.href = url;
Object.keys(options.attributes).forEach(function (key) {
linkElement.setAttribute(key, options.attributes[key]);
});
options.insert(linkElement);
return function (newUrl) {
if (typeof newUrl === "string") {
linkElement.href = newUrl;
} else {
linkElement.parentNode.removeChild(linkElement);
}
};
};

View File

@@ -0,0 +1,84 @@
"use strict";
var stylesInDOM = [];
function getIndexByIdentifier(identifier) {
var result = -1;
for (var i = 0; i < stylesInDOM.length; i++) {
if (stylesInDOM[i].identifier === identifier) {
result = i;
break;
}
}
return result;
}
function modulesToDom(list, options) {
var idCountMap = {};
var identifiers = [];
for (var i = 0; i < list.length; i++) {
var item = list[i];
var id = options.base ? item[0] + options.base : item[0];
var count = idCountMap[id] || 0;
var identifier = "".concat(id, " ").concat(count);
idCountMap[id] = count + 1;
var indexByIdentifier = getIndexByIdentifier(identifier);
var obj = {
css: item[1],
media: item[2],
sourceMap: item[3],
supports: item[4],
layer: item[5]
};
if (indexByIdentifier !== -1) {
stylesInDOM[indexByIdentifier].references++;
stylesInDOM[indexByIdentifier].updater(obj);
} else {
var updater = addElementStyle(obj, options);
options.byIndex = i;
stylesInDOM.splice(i, 0, {
identifier: identifier,
updater: updater,
references: 1
});
}
identifiers.push(identifier);
}
return identifiers;
}
function addElementStyle(obj, options) {
var api = options.domAPI(options);
api.update(obj);
var updater = function updater(newObj) {
if (newObj) {
if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {
return;
}
api.update(obj = newObj);
} else {
api.remove();
}
};
return updater;
}
module.exports = function (list, options) {
options = options || {};
list = list || [];
var lastIdentifiers = modulesToDom(list, options);
return function update(newList) {
newList = newList || [];
for (var i = 0; i < lastIdentifiers.length; i++) {
var identifier = lastIdentifiers[i];
var index = getIndexByIdentifier(identifier);
stylesInDOM[index].references--;
}
var newLastIdentifiers = modulesToDom(newList, options);
for (var _i = 0; _i < lastIdentifiers.length; _i++) {
var _identifier = lastIdentifiers[_i];
var _index = getIndexByIdentifier(_identifier);
if (stylesInDOM[_index].references === 0) {
stylesInDOM[_index].updater();
stylesInDOM.splice(_index, 1);
}
}
lastIdentifiers = newLastIdentifiers;
};
};

View File

@@ -0,0 +1,34 @@
"use strict";
var memo = {};
/* istanbul ignore next */
function getTarget(target) {
if (typeof memo[target] === "undefined") {
var styleTarget = document.querySelector(target);
// Special case to return head of iframe instead of iframe itself
if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
try {
// This will throw an exception if access to iframe is blocked
// due to cross-origin restrictions
styleTarget = styleTarget.contentDocument.head;
} catch (e) {
// istanbul ignore next
styleTarget = null;
}
}
memo[target] = styleTarget;
}
return memo[target];
}
/* istanbul ignore next */
function insertBySelector(insert, style) {
var target = getTarget(insert);
if (!target) {
throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
}
target.appendChild(style);
}
module.exports = insertBySelector;

View File

@@ -0,0 +1,10 @@
"use strict";
/* istanbul ignore next */
function insertStyleElement(options) {
var element = document.createElement("style");
options.setAttributes(element, options.attributes);
options.insert(element, options.options);
return element;
}
module.exports = insertStyleElement;

View File

@@ -0,0 +1,28 @@
"use strict";
function isEqualLocals(a, b, isNamedExport) {
if (!a && b || a && !b) {
return false;
}
var p;
for (p in a) {
if (isNamedExport && p === "default") {
// eslint-disable-next-line no-continue
continue;
}
if (a[p] !== b[p]) {
return false;
}
}
for (p in b) {
if (isNamedExport && p === "default") {
// eslint-disable-next-line no-continue
continue;
}
if (!a[p]) {
return false;
}
}
return true;
}
module.exports = isEqualLocals;

17
node_modules/style-loader/dist/runtime/isOldIE.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
"use strict";
var memo;
/* istanbul ignore next */
function isOldIE() {
if (typeof memo === "undefined") {
// Test for IE <= 9 as proposed by Browserhacks
// @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805
// Tests for existence of standard globals is to allow style-loader
// to operate correctly into non-standard environments
// @see https://github.com/webpack-contrib/style-loader/issues/177
memo = Boolean(typeof window !== "undefined" && typeof document !== "undefined" && document.all && !window.atob);
}
return memo;
}
module.exports = isOldIE;

View File

@@ -0,0 +1,13 @@
"use strict";
/* istanbul ignore next */
function setAttributesWithoutAttributes(styleElement, attributes) {
var nonce = typeof __webpack_nonce__ !== "undefined" ? __webpack_nonce__ : null;
if (nonce) {
attributes.nonce = nonce;
}
Object.keys(attributes).forEach(function (key) {
styleElement.setAttribute(key, attributes[key]);
});
}
module.exports = setAttributesWithoutAttributes;

View File

@@ -0,0 +1,9 @@
"use strict";
/* istanbul ignore next */
function setAttributesWithoutAttributes(styleElement, attributes) {
Object.keys(attributes).forEach(function (key) {
styleElement.setAttribute(key, attributes[key]);
});
}
module.exports = setAttributesWithoutAttributes;

View File

@@ -0,0 +1,10 @@
"use strict";
/* istanbul ignore next */
function setAttributesWithoutAttributes(styleElement) {
var nonce = typeof __webpack_nonce__ !== "undefined" ? __webpack_nonce__ : null;
if (nonce) {
styleElement.setAttribute("nonce", nonce);
}
}
module.exports = setAttributesWithoutAttributes;

View File

@@ -0,0 +1,86 @@
"use strict";
/* istanbul ignore next */
var replaceText = function replaceText() {
var textStore = [];
return function replace(index, replacement) {
textStore[index] = replacement;
return textStore.filter(Boolean).join("\n");
};
}();
/* istanbul ignore next */
function apply(styleElement, index, remove, obj) {
var css;
if (remove) {
css = "";
} else {
css = "";
if (obj.supports) {
css += "@supports (".concat(obj.supports, ") {");
}
if (obj.media) {
css += "@media ".concat(obj.media, " {");
}
var needLayer = typeof obj.layer !== "undefined";
if (needLayer) {
css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {");
}
css += obj.css;
if (needLayer) {
css += "}";
}
if (obj.media) {
css += "}";
}
if (obj.supports) {
css += "}";
}
}
// For old IE
/* istanbul ignore if */
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = replaceText(index, css);
} else {
var cssNode = document.createTextNode(css);
var childNodes = styleElement.childNodes;
if (childNodes[index]) {
styleElement.removeChild(childNodes[index]);
}
if (childNodes.length) {
styleElement.insertBefore(cssNode, childNodes[index]);
} else {
styleElement.appendChild(cssNode);
}
}
}
var singletonData = {
singleton: null,
singletonCounter: 0
};
/* istanbul ignore next */
function domAPI(options) {
if (typeof document === "undefined") return {
update: function update() {},
remove: function remove() {}
};
// eslint-disable-next-line no-undef,no-use-before-define
var styleIndex = singletonData.singletonCounter++;
var styleElement =
// eslint-disable-next-line no-undef,no-use-before-define
singletonData.singleton || (
// eslint-disable-next-line no-undef,no-use-before-define
singletonData.singleton = options.insertStyleElement(options));
return {
update: function update(obj) {
apply(styleElement, styleIndex, false, obj);
},
remove: function remove(obj) {
apply(styleElement, styleIndex, true, obj);
}
};
}
module.exports = domAPI;

61
node_modules/style-loader/dist/runtime/styleDomAPI.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
"use strict";
/* istanbul ignore next */
function apply(styleElement, options, obj) {
var css = "";
if (obj.supports) {
css += "@supports (".concat(obj.supports, ") {");
}
if (obj.media) {
css += "@media ".concat(obj.media, " {");
}
var needLayer = typeof obj.layer !== "undefined";
if (needLayer) {
css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {");
}
css += obj.css;
if (needLayer) {
css += "}";
}
if (obj.media) {
css += "}";
}
if (obj.supports) {
css += "}";
}
var sourceMap = obj.sourceMap;
if (sourceMap && typeof btoa !== "undefined") {
css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
}
// For old IE
/* istanbul ignore if */
options.styleTagTransform(css, styleElement, options.options);
}
function removeStyleElement(styleElement) {
// istanbul ignore if
if (styleElement.parentNode === null) {
return false;
}
styleElement.parentNode.removeChild(styleElement);
}
/* istanbul ignore next */
function domAPI(options) {
if (typeof document === "undefined") {
return {
update: function update() {},
remove: function remove() {}
};
}
var styleElement = options.insertStyleElement(options);
return {
update: function update(obj) {
apply(styleElement, options, obj);
},
remove: function remove() {
removeStyleElement(styleElement);
}
};
}
module.exports = domAPI;

View File

@@ -0,0 +1,14 @@
"use strict";
/* istanbul ignore next */
function styleTagTransform(css, styleElement) {
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = css;
} else {
while (styleElement.firstChild) {
styleElement.removeChild(styleElement.firstChild);
}
styleElement.appendChild(document.createTextNode(css));
}
}
module.exports = styleTagTransform;

191
node_modules/style-loader/dist/utils.js generated vendored Normal file
View File

@@ -0,0 +1,191 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getExportLazyStyleCode = getExportLazyStyleCode;
exports.getExportStyleCode = getExportStyleCode;
exports.getImportInsertBySelectorCode = getImportInsertBySelectorCode;
exports.getImportInsertStyleElementCode = getImportInsertStyleElementCode;
exports.getImportIsOldIECode = getImportIsOldIECode;
exports.getImportLinkAPICode = getImportLinkAPICode;
exports.getImportLinkContentCode = getImportLinkContentCode;
exports.getImportStyleAPICode = getImportStyleAPICode;
exports.getImportStyleContentCode = getImportStyleContentCode;
exports.getImportStyleDomAPICode = getImportStyleDomAPICode;
exports.getInsertOptionCode = getInsertOptionCode;
exports.getLinkHmrCode = getLinkHmrCode;
exports.getSetAttributesCode = getSetAttributesCode;
exports.getStyleHmrCode = getStyleHmrCode;
exports.getStyleTagTransformFn = getStyleTagTransformFn;
exports.getStyleTagTransformFnCode = getStyleTagTransformFnCode;
exports.getdomAPI = getdomAPI;
exports.stringifyRequest = stringifyRequest;
var _path = _interopRequireDefault(require("path"));
var _isEqualLocals = _interopRequireDefault(require("./runtime/isEqualLocals"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function stringifyRequest(loaderContext, request) {
return JSON.stringify(loaderContext.utils.contextify(loaderContext.context, request));
}
function getImportLinkAPICode(esModule, loaderContext) {
const modulePath = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/injectStylesIntoLinkTag.js")}`);
return esModule ? `import API from ${modulePath};` : `var API = require(${modulePath});`;
}
function getImportLinkContentCode(esModule, loaderContext, request) {
const modulePath = stringifyRequest(loaderContext, `!!${request}`);
return esModule ? `import content from ${modulePath};` : `var content = require(${modulePath});`;
}
function getImportStyleAPICode(esModule, loaderContext) {
const modulePath = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/injectStylesIntoStyleTag.js")}`);
return esModule ? `import API from ${modulePath};` : `var API = require(${modulePath});`;
}
function getImportStyleDomAPICode(esModule, loaderContext, isSingleton, isAuto) {
const styleAPI = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/styleDomAPI.js")}`);
const singletonAPI = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/singletonStyleDomAPI.js")}`);
if (isAuto) {
return esModule ? `import domAPI from ${styleAPI};
import domAPISingleton from ${singletonAPI};` : `var domAPI = require(${styleAPI});
var domAPISingleton = require(${singletonAPI});`;
}
return esModule ? `import domAPI from ${isSingleton ? singletonAPI : styleAPI};` : `var domAPI = require(${isSingleton ? singletonAPI : styleAPI});`;
}
function getImportStyleContentCode(esModule, loaderContext, request) {
const modulePath = stringifyRequest(loaderContext, `!!${request}`);
return esModule ? `import content, * as namedExport from ${modulePath};` : `var content = require(${modulePath});`;
}
function getImportInsertBySelectorCode(esModule, loaderContext, insertType, options) {
if (insertType === "module-path") {
const modulePath = stringifyRequest(loaderContext, `${options.insert}`);
loaderContext.addBuildDependency(options.insert);
return esModule ? `import insertFn from ${modulePath};` : `var insertFn = require(${modulePath});`;
}
const modulePath = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/insertBySelector.js")}`);
return esModule ? `import insertFn from ${modulePath};` : `var insertFn = require(${modulePath});`;
}
function getInsertOptionCode(insertType, options) {
if (insertType === "module-path") {
return `options.insert = insertFn;`;
}
const insert = options.insert ? JSON.stringify(options.insert) : '"head"';
return `options.insert = insertFn.bind(null, ${insert});`;
}
function getImportInsertStyleElementCode(esModule, loaderContext) {
const modulePath = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/insertStyleElement.js")}`);
return esModule ? `import insertStyleElement from ${modulePath};` : `var insertStyleElement = require(${modulePath});`;
}
function getStyleHmrCode(esModule, loaderContext, request, lazy) {
const modulePath = stringifyRequest(loaderContext, `!!${request}`);
return `
if (module.hot) {
if (!content.locals || module.hot.invalidate) {
var isEqualLocals = ${_isEqualLocals.default.toString()};
var isNamedExport = ${esModule ? "!content.locals" : false};
var oldLocals = isNamedExport ? namedExport : content.locals;
module.hot.accept(
${modulePath},
function () {
${esModule ? `if (!isEqualLocals(oldLocals, isNamedExport ? namedExport : content.locals, isNamedExport)) {
module.hot.invalidate();
return;
}
oldLocals = isNamedExport ? namedExport : content.locals;
${lazy ? `if (update && refs > 0) {
update(content);
}` : `update(content);`}` : `content = require(${modulePath});
content = content.__esModule ? content.default : content;
${lazy ? "" : `if (typeof content === 'string') {
content = [[module.id, content, '']];
}`}
if (!isEqualLocals(oldLocals, content.locals)) {
module.hot.invalidate();
return;
}
oldLocals = content.locals;
${lazy ? `if (update && refs > 0) {
update(content);
}` : `update(content);`}`}
}
)
}
module.hot.dispose(function() {
${lazy ? `if (update) {
update();
}` : `update();`}
});
}
`;
}
function getLinkHmrCode(esModule, loaderContext, request) {
const modulePath = stringifyRequest(loaderContext, `!!${request}`);
return `
if (module.hot) {
module.hot.accept(
${modulePath},
function() {
${esModule ? "update(content);" : `content = require(${modulePath});
content = content.__esModule ? content.default : content;
update(content);`}
}
);
module.hot.dispose(function() {
update();
});
}`;
}
function getdomAPI(isAuto) {
return isAuto ? "isOldIE() ? domAPISingleton : domAPI" : "domAPI";
}
function getImportIsOldIECode(esModule, loaderContext) {
const modulePath = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/isOldIE.js")}`);
return esModule ? `import isOldIE from ${modulePath};` : `var isOldIE = require(${modulePath});`;
}
function getStyleTagTransformFnCode(esModule, loaderContext, options, isSingleton) {
if (isSingleton) {
return "";
}
if (typeof options.styleTagTransform !== "undefined") {
const modulePath = stringifyRequest(loaderContext, `${options.styleTagTransform}`);
loaderContext.addBuildDependency(options.styleTagTransform);
return esModule ? `import styleTagTransformFn from ${modulePath};` : `var styleTagTransformFn = require(${modulePath});`;
}
const modulePath = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/styleTagTransform.js")}`);
return esModule ? `import styleTagTransformFn from ${modulePath};` : `var styleTagTransformFn = require(${modulePath});`;
}
function getStyleTagTransformFn(options, isSingleton) {
return isSingleton ? "" : `options.styleTagTransform = styleTagTransformFn`;
}
function getExportStyleCode(esModule, loaderContext, request) {
const modulePath = stringifyRequest(loaderContext, `!!${request}`);
return esModule ? `export * from ${modulePath};
export default content && content.locals ? content.locals : undefined;` : "module.exports = content && content.locals || {};";
}
function getExportLazyStyleCode(esModule, loaderContext, request) {
const modulePath = stringifyRequest(loaderContext, `!!${request}`);
return esModule ? `export * from ${modulePath};
export default exported;` : "module.exports = exported;";
}
function getSetAttributesCode(esModule, loaderContext, options) {
let modulePath;
if (typeof options.attributes !== "undefined") {
modulePath = options.attributes.nonce !== "undefined" ? stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/setAttributesWithAttributesAndNonce.js")}`) : stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/setAttributesWithAttributes.js")}`);
} else {
modulePath = stringifyRequest(loaderContext, `!${_path.default.join(__dirname, "runtime/setAttributesWithoutAttributes.js")}`);
}
return esModule ? `import setAttributes from ${modulePath};` : `var setAttributes = require(${modulePath});`;
}
// eslint-disable-next-line import/prefer-default-export

85
node_modules/style-loader/package.json generated vendored Normal file
View File

@@ -0,0 +1,85 @@
{
"name": "style-loader",
"version": "4.0.0",
"description": "style loader module for webpack",
"license": "MIT",
"repository": "webpack-contrib/style-loader",
"author": "Tobias Koppers @sokra",
"homepage": "https://github.com/webpack-contrib/style-loader",
"bugs": "https://github.com/webpack-contrib/style-loader/issues",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"main": "dist/cjs.js",
"engines": {
"node": ">= 18.12.0"
},
"scripts": {
"start": "npm run build -- -w",
"clean": "del-cli dist",
"validate:runtime": "es-check es3 \"dist/runtime/**/*.js\"",
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production babel src -d dist --copy-files",
"postbuild": "npm run validate:runtime",
"commitlint": "commitlint --from=master",
"security": "npm audit --production",
"lint:prettier": "prettier --cache --list-different .",
"lint:js": "eslint --cache .",
"lint:spelling": "cspell --cache --no-must-find-files --quiet \"**/*.*\"",
"lint": "npm-run-all -l -p \"lint:**\"",
"fix:js": "npm run lint:js -- --fix",
"fix:prettier": "npm run lint:prettier -- --write",
"fix": "npm-run-all -l fix:js fix:prettier",
"test:only": "cross-env NODE_ENV=test jest",
"test:watch": "npm run test:only -- --watch",
"test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
"test:manual": "npm run build && webpack serve ./test/manual/src/index.js --open --config test/manual/webpack.config.js",
"pretest": "npm run lint",
"test": "npm run test:coverage",
"prepare": "husky && npm run build",
"release": "standard-version"
},
"files": [
"dist"
],
"peerDependencies": {
"webpack": "^5.27.0"
},
"devDependencies": {
"@babel/cli": "^7.24.1",
"@babel/core": "^7.24.4",
"@babel/preset-env": "^7.24.4",
"@commitlint/cli": "^19.2.1",
"@commitlint/config-conventional": "^19.1.0",
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
"babel-jest": "^29.7.0",
"cross-env": "^7.0.3",
"cspell": "^8.6.1",
"css-loader": "^7.0.0",
"del-cli": "^5.1.0",
"es-check": "^7.1.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"file-loader": "^6.2.0",
"husky": "^9.0.11",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jsdom": "^24.0.0",
"lint-staged": "^15.2.2",
"memfs": "^4.8.1",
"npm-run-all": "^4.1.5",
"prettier": "^3.2.5",
"sass": "^1.74.1",
"sass-loader": "^14.1.1",
"semver": "^7.6.0",
"standard-version": "^9.5.0",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
},
"keywords": [
"webpack"
]
}

20
package-lock.json generated
View File

@@ -19,8 +19,10 @@
"@babel/preset-env": "^7.23.0",
"@vue/cli-service": "^5.0.0",
"babel-loader": "^9.1.0",
"css-loader": "^6.8.0",
"css-loader": "^6.11.0",
"eslint": "^8.50.0",
"html-webpack-plugin": "^5.6.4",
"style-loader": "^4.0.0",
"vue-loader": "^17.3.0",
"vue-template-compiler": "^2.7.0",
"webpack": "^5.89.0",
@@ -9371,6 +9373,22 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/style-loader": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/style-loader/-/style-loader-4.0.0.tgz",
"integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==",
"dev": true,
"engines": {
"node": ">= 18.12.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^5.27.0"
}
},
"node_modules/stylehacks": {
"version": "5.1.1",
"resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz",

View File

@@ -17,22 +17,24 @@
"author": "",
"license": "MIT",
"dependencies": {
"vue": "^3.4.0",
"vue-router": "^4.2.0",
"axios": "^1.6.0",
"element-plus": "^2.4.0"
"element-plus": "^2.4.0",
"vue": "^3.4.0",
"vue-router": "^4.2.0"
},
"devDependencies": {
"@babel/core": "^7.23.0",
"@babel/preset-env": "^7.23.0",
"@vue/cli-service": "^5.0.0",
"babel-loader": "^9.1.0",
"css-loader": "^6.11.0",
"eslint": "^8.50.0",
"html-webpack-plugin": "^5.6.4",
"style-loader": "^4.0.0",
"vue-loader": "^17.3.0",
"vue-template-compiler": "^2.7.0",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.0",
"webpack-dev-server": "^4.15.0",
"eslint": "^8.50.0",
"babel-loader": "^9.1.0",
"css-loader": "^6.8.0",
"vue-loader": "^17.3.0",
"vue-template-compiler": "^2.7.0"
"webpack-dev-server": "^4.15.0"
}
}

View File

@@ -1,58 +1,20 @@
<template>
<div id="app">
<header class="header">
<h1>猪场管理系统</h1>
<nav class="navigation">
<el-menu mode="horizontal" :router="true">
<el-menu-item index="/">首页</el-menu-item>
<el-menu-item index="/devices">设备管理</el-menu-item>
</el-menu>
</nav>
</header>
<main class="main-content">
<router-view />
</main>
<footer class="footer">
<p>© 2025 猪场管理系统. All rights reserved.</p>
</footer>
</div>
<MainLayout />
</template>
<script>
import MainLayout from './layouts/MainLayout.vue';
export default {
name: 'App'
name: 'App',
components: {
MainLayout
}
};
</script>
<style scoped>
.header {
background-color: #409EFF;
color: white;
padding: 1rem;
box-shadow: 0 2px 4px rgba(0,0,0,.1);
}
.header h1 {
text-align: center;
margin-bottom: 1rem;
}
.navigation {
max-width: 1200px;
margin: 0 auto;
}
.main-content {
max-width: 1200px;
margin: 2rem auto;
padding: 0 1rem;
min-height: calc(100vh - 100px);
}
.footer {
text-align: center;
padding: 1rem;
background-color: #f5f5f5;
border-top: 1px solid #ebeef5;
<style>
#app {
min-height: 100vh;
}
</style>

53
src/api/device.js Normal file
View File

@@ -0,0 +1,53 @@
import http from '../utils/http.js';
/**
* 设备管理API
*/
export class DeviceApi {
/**
* 获取设备列表
* @returns {Promise} 设备列表
*/
static list() {
return http.get('/devices');
}
/**
* 创建新设备
* @param {Object} deviceData 设备数据
* @returns {Promise} 创建结果
*/
static create(deviceData) {
return http.post('/devices', deviceData);
}
/**
* 获取设备详情
* @param {string|number} id 设备ID
* @returns {Promise} 设备详情
*/
static get(id) {
return http.get(`/devices/${id}`);
}
/**
* 更新设备信息
* @param {string|number} id 设备ID
* @param {Object} deviceData 设备数据
* @returns {Promise} 更新结果
*/
static update(id, deviceData) {
return http.put(`/devices/${id}`, deviceData);
}
/**
* 删除设备
* @param {string|number} id 设备ID
* @returns {Promise} 删除结果
*/
static delete(id) {
return http.delete(`/devices/${id}`);
}
}
export default DeviceApi;

17
src/api/index.js Normal file
View File

@@ -0,0 +1,17 @@
import DeviceApi from './device.js';
import PlanApi from './plan.js';
import UserApi from './user.js';
/**
* API客户端
*/
export class ApiClient {
constructor() {
this.devices = DeviceApi;
this.plans = PlanApi;
this.users = UserApi;
}
}
// 导出API客户端实例
export default new ApiClient();

71
src/api/plan.js Normal file
View File

@@ -0,0 +1,71 @@
import http from '../utils/http.js';
/**
* 计划管理API
*/
export class PlanApi {
/**
* 获取计划列表
* @returns {Promise} 计划列表
*/
static list() {
return http.get('/plans');
}
/**
* 创建新计划
* @param {Object} planData 计划数据
* @returns {Promise} 创建结果
*/
static create(planData) {
return http.post('/plans', planData);
}
/**
* 获取计划详情
* @param {string|number} id 计划ID
* @returns {Promise} 计划详情
*/
static get(id) {
return http.get(`/plans/${id}`);
}
/**
* 更新计划信息
* @param {string|number} id 计划ID
* @param {Object} planData 计划数据
* @returns {Promise} 更新结果
*/
static update(id, planData) {
return http.put(`/plans/${id}`, planData);
}
/**
* 删除计划
* @param {string|number} id 计划ID
* @returns {Promise} 删除结果
*/
static delete(id) {
return http.delete(`/plans/${id}`);
}
/**
* 启动计划
* @param {string|number} id 计划ID
* @returns {Promise} 启动结果
*/
static start(id) {
return http.post(`/plans/${id}/start`);
}
/**
* 停止计划
* @param {string|number} id 计划ID
* @returns {Promise} 停止结果
*/
static stop(id) {
return http.post(`/plans/${id}/stop`);
}
}
export default PlanApi;

26
src/api/user.js Normal file
View File

@@ -0,0 +1,26 @@
import http from '../utils/http.js';
/**
* 用户管理API
*/
export class UserApi {
/**
* 创建新用户
* @param {Object} userData 用户数据
* @returns {Promise} 创建结果
*/
static create(userData) {
return http.post('/users', userData);
}
/**
* 用户登录
* @param {Object} credentials 登录凭证 {username, password}
* @returns {Promise} 登录结果
*/
static login(credentials) {
return http.post('/users/login', credentials);
}
}
export default UserApi;

View File

@@ -3,7 +3,7 @@
<el-card>
<template #header>
<div class="card-header">
<span>设备管理</span>
<h2 class="page-title">设备管理</h2>
<el-button type="primary" @click="addDevice">添加设备</el-button>
</div>
</template>
@@ -211,10 +211,23 @@ export default {
</script>
<style scoped>
.device-list {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
}
.page-title {
margin: 0;
font-size: 1.5rem;
font-weight: bold;
}
.dialog-footer {
@@ -233,4 +246,15 @@ export default {
.retry-btn {
margin-top: 15px;
}
@media (max-width: 768px) {
.device-list {
padding: 10px;
}
.card-header {
flex-direction: column;
gap: 15px;
}
}
</style>

View File

@@ -64,13 +64,26 @@ export default {
</script>
<style scoped>
.home {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.welcome-card {
margin-bottom: 2rem;
}
.card-header {
font-size: 1.2rem;
font-size: 1.5rem;
font-weight: bold;
text-align: center;
padding: 10px 0;
}
.content {
font-size: 1rem;
line-height: 1.6;
}
.content p {
@@ -99,4 +112,14 @@ export default {
font-size: 0.9rem;
color: #909399;
}
@media (max-width: 768px) {
.home {
padding: 10px;
}
.el-col {
margin-bottom: 15px;
}
}
</style>

220
src/components/PlanList.vue Normal file
View File

@@ -0,0 +1,220 @@
<template>
<div class="plan-list">
<el-card>
<template #header>
<div class="card-header">
<h2 class="page-title">计划管理</h2>
<el-button type="primary" @click="addPlan">添加计划</el-button>
</div>
</template>
<el-table :data="plans" style="width: 100%">
<el-table-column prop="id" label="计划ID" width="80" />
<el-table-column prop="name" label="计划名称" width="180" />
<el-table-column prop="description" label="描述" />
<el-table-column prop="execution_type" label="执行类型" width="120">
<template #default="scope">
<el-tag v-if="scope.row.execution_type === 'automatic'">自动</el-tag>
<el-tag v-else>手动</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template #default="scope">
<el-tag v-if="scope.row.status === 0" type="success">启用</el-tag>
<el-tag v-else-if="scope.row.status === 1" type="warning">禁用</el-tag>
<el-tag v-else type="info">已完成</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="scope">
<el-button size="small" @click="editPlan(scope.row)">编辑</el-button>
<el-button size="small" @click="startPlan(scope.row)" :loading="startingPlanId === scope.row.id">
启动
</el-button>
<el-button size="small" type="danger" @click="deletePlan(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 添加/编辑计划对话框 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="50%">
<el-form :model="currentPlan" label-width="120px">
<el-form-item label="计划名称">
<el-input v-model="currentPlan.name" />
</el-form-item>
<el-form-item label="描述">
<el-input v-model="currentPlan.description" type="textarea" />
</el-form-item>
<el-form-item label="执行类型">
<el-select v-model="currentPlan.execution_type" placeholder="请选择执行类型">
<el-option label="自动执行" value="automatic" />
<el-option label="手动执行" value="manual" />
</el-select>
</el-form-item>
<el-form-item label="内容类型" v-if="!isEdit">
<el-radio-group v-model="contentType">
<el-radio label="tasks">任务</el-radio>
<el-radio label="sub_plans">子计划</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="savePlan">保存</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import apiClient from '../api/index.js';
export default {
name: 'PlanList',
data() {
return {
plans: [],
dialogVisible: false,
dialogTitle: '',
isEdit: false,
contentType: 'tasks',
currentPlan: {
id: null,
name: '',
description: '',
execution_type: 'automatic',
content_type: 'tasks'
},
startingPlanId: null
};
},
async mounted() {
await this.loadPlans();
},
methods: {
// 加载计划列表
async loadPlans() {
try {
const response = await apiClient.plans.list();
this.plans = response.data?.plans || [];
} catch (err) {
this.$message.error('加载计划列表失败: ' + (err.message || '未知错误'));
console.error('加载计划列表失败:', err);
}
},
addPlan() {
this.dialogTitle = '添加计划';
this.currentPlan = {
id: null,
name: '',
description: '',
execution_type: 'automatic'
};
this.isEdit = false;
this.dialogVisible = true;
},
editPlan(plan) {
this.dialogTitle = '编辑计划';
this.currentPlan = { ...plan };
this.isEdit = true;
this.dialogVisible = true;
},
async deletePlan(plan) {
try {
await this.$confirm('确认删除该计划吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
await apiClient.plans.delete(plan.id);
this.$message.success('删除成功');
await this.loadPlans();
} catch (err) {
if (err !== 'cancel') {
this.$message.error('删除失败: ' + (err.message || '未知错误'));
}
}
},
async startPlan(plan) {
try {
this.startingPlanId = plan.id;
await apiClient.plans.start(plan.id);
this.$message.success('计划启动成功');
await this.loadPlans();
} catch (err) {
this.$message.error('启动失败: ' + (err.message || '未知错误'));
} finally {
this.startingPlanId = null;
}
},
async savePlan() {
try {
if (this.isEdit) {
// 编辑计划
await apiClient.plans.update(this.currentPlan.id, this.currentPlan);
this.$message.success('计划更新成功');
} else {
// 添加新计划
const planData = {
...this.currentPlan,
content_type: this.contentType
};
await apiClient.plans.create(planData);
this.$message.success('计划添加成功');
}
this.dialogVisible = false;
await this.loadPlans();
} catch (err) {
this.$message.error('保存失败: ' + (err.message || '未知错误'));
}
}
}
};
</script>
<style scoped>
.plan-list {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
}
.page-title {
margin: 0;
font-size: 1.5rem;
font-weight: bold;
}
.dialog-footer {
text-align: right;
}
@media (max-width: 768px) {
.plan-list {
padding: 10px;
}
.card-header {
flex-direction: column;
gap: 15px;
}
}
</style>

208
src/layouts/MainLayout.vue Normal file
View File

@@ -0,0 +1,208 @@
<template>
<el-container class="layout-container">
<!-- 侧边栏菜单 -->
<el-aside :width="isCollapse ? '64px' : '200px'" class="sidebar">
<div class="logo" @click="toggleCollapse">
<h2 v-if="!isCollapse" class="logo-text">猪场管理系统</h2>
<el-icon v-else class="logo-icon"><Menu /></el-icon>
</div>
<el-menu
:default-active="activeMenu"
class="sidebar-menu"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
:collapse="isCollapse"
:collapse-transition="false"
router
>
<el-menu-item index="/">
<el-icon><House /></el-icon>
<template #title>首页</template>
</el-menu-item>
<el-menu-item index="/devices">
<el-icon><Monitor /></el-icon>
<template #title>设备管理</template>
</el-menu-item>
<el-menu-item index="/plans">
<el-icon><Calendar /></el-icon>
<template #title>计划管理</template>
</el-menu-item>
</el-menu>
</el-aside>
<!-- 主区域 -->
<el-container>
<!-- 头部 -->
<el-header class="header">
<div class="header-content">
<div class="header-left">
<el-button link @click="toggleCollapse">
<el-icon><Expand v-if="isCollapse" /><Fold v-else /></el-icon>
</el-button>
<h3 class="page-title">{{ currentPageTitle }}</h3>
</div>
<div class="user-info">
<el-dropdown>
<span class="el-dropdown-link">
管理员 <el-icon><ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人信息</el-dropdown-item>
<el-dropdown-item>退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</el-header>
<!-- 主内容区 -->
<el-main class="main-content">
<router-view />
</el-main>
<!-- 底部 -->
<el-footer class="footer">
<p>© 2025 猪场管理系统. All rights reserved.</p>
</el-footer>
</el-container>
</el-container>
</template>
<script>
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { House, Monitor, Calendar, ArrowDown, Menu, Fold, Expand } from '@element-plus/icons-vue';
export default {
name: 'MainLayout',
components: {
House,
Monitor,
Calendar,
ArrowDown,
Menu,
Fold,
Expand
},
setup() {
const route = useRoute();
const isCollapse = ref(false);
// 切换侧边栏折叠状态
const toggleCollapse = () => {
isCollapse.value = !isCollapse.value;
};
// 当前激活的菜单项
const activeMenu = computed(() => {
return route.path;
});
// 当前页面标题
const currentPageTitle = computed(() => {
const routeMap = {
'/': '系统首页',
'/devices': '设备管理',
'/plans': '计划管理'
};
return routeMap[route.path] || '猪场管理系统';
});
return {
isCollapse,
activeMenu,
currentPageTitle,
toggleCollapse
};
}
};
</script>
<style scoped>
.layout-container {
min-height: 100vh;
}
.sidebar {
background-color: #545c64;
box-shadow: 2px 0 6px rgba(0, 21, 18, 0.1);
transition: width 0.3s ease;
overflow: hidden;
}
.logo {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
color: white;
background-color: #454d54;
cursor: pointer;
transition: all 0.3s ease;
}
.logo-text {
margin: 0;
font-size: 18px;
white-space: nowrap;
}
.logo-icon {
font-size: 24px;
}
.sidebar-menu {
border-right: none;
height: calc(100% - 60px);
}
.sidebar-menu:not(.el-menu--collapse) {
width: 200px;
}
.header {
background-color: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 18, 0.1);
padding: 0;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
padding: 0 20px;
}
.header-left {
display: flex;
align-items: center;
gap: 15px;
}
.page-title {
margin: 0;
font-size: 18px;
font-weight: 500;
}
.user-info {
margin-right: 10px;
}
.main-content {
background-color: #f5f5f5;
padding: 20px;
}
.footer {
background-color: #fff;
color: #666;
text-align: center;
font-size: 14px;
border-top: 1px solid #eee;
}
</style>

View File

@@ -4,20 +4,18 @@ import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import App from './App.vue';
import DeviceList from './components/DeviceList.vue';
import Home from './components/Home.vue';
import DeviceList from './components/DeviceList.vue';
import PlanList from './components/PlanList.vue';
// 导入全局样式
import './assets/styles/main.css';
// 引入新创建的服务和工具(示例)
import ApiService from './services/apiService'; // 示例服务
import * as Utils from './utils/helpers'; // 示例工具函数
// 配置路由
const routes = [
{ path: '/', component: Home },
{ path: '/devices', component: DeviceList }
{ path: '/devices', component: DeviceList },
{ path: '/plans', component: PlanList }
];
const router = createRouter({

View File

@@ -1,5 +1,4 @@
import http from '../utils/http.js';
import API_CONFIG from '../config/api.js';
import apiClient from '../api/index.js';
class DeviceService {
/**
@@ -8,7 +7,7 @@ class DeviceService {
*/
async getDevices() {
try {
const response = await http.get(API_CONFIG.ENDPOINTS.DEVICES);
const response = await apiClient.devices.list();
return response.data || [];
} catch (error) {
console.error('获取设备列表失败:', error);
@@ -23,7 +22,7 @@ class DeviceService {
*/
async createDevice(device) {
try {
const response = await http.post(API_CONFIG.ENDPOINTS.DEVICES, device);
const response = await apiClient.devices.create(device);
return response.data;
} catch (error) {
console.error('创建设备失败:', error);
@@ -39,7 +38,7 @@ class DeviceService {
*/
async updateDevice(deviceId, device) {
try {
const response = await http.put(`${API_CONFIG.ENDPOINTS.DEVICES}/${deviceId}`, device);
const response = await apiClient.devices.update(deviceId, device);
return response.data;
} catch (error) {
console.error('更新设备失败:', error);
@@ -54,7 +53,7 @@ class DeviceService {
*/
async deleteDevice(deviceId) {
try {
await http.delete(`${API_CONFIG.ENDPOINTS.DEVICES}/${deviceId}`);
await apiClient.devices.delete(deviceId);
} catch (error) {
console.error('删除设备失败:', error);
throw error;

View File

@@ -1,5 +1,6 @@
const { VueLoaderPlugin } = require('vue-loader');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = (env, argv) => {
const isDevelopment = argv.mode === 'development';
@@ -8,7 +9,8 @@ module.exports = (env, argv) => {
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
path: path.resolve(__dirname, 'dist'),
clean: true
},
module: {
rules: [
@@ -31,13 +33,20 @@ module.exports = (env, argv) => {
]
},
plugins: [
new VueLoaderPlugin()
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html'
})
],
devServer: {
static: './dist',
static: {
directory: path.join(__dirname, 'dist'),
},
hot: true,
open: true,
historyApiFallback: true
historyApiFallback: true,
port: 8080
},
resolve: {
alias: {