This commit is contained in:
aaron 2025-03-21 14:23:46 +08:00
parent 20f94f9618
commit 9610f41e92
8 changed files with 2489 additions and 328 deletions

712
package-lock.json generated
View File

@ -12,6 +12,7 @@
"@vue/cli-service": "^5.0.8",
"ant-design-vue": "^3.2.20",
"axios": "^1.7.9",
"md-editor-v3": "^4.8.3",
"nprogress": "^0.2.0",
"qrcode.vue": "^3.6.0",
"vue": "^3.3.4",
@ -178,6 +179,360 @@
"node": ">=6.9.0"
}
},
"node_modules/@codemirror/autocomplete": {
"version": "6.18.6",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0"
}
},
"node_modules/@codemirror/commands": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.0.tgz",
"integrity": "sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.27.0",
"@lezer/common": "^1.1.0"
}
},
"node_modules/@codemirror/lang-angular": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@codemirror/lang-angular/-/lang-angular-0.1.3.tgz",
"integrity": "sha512-xgeWGJQQl1LyStvndWtruUvb4SnBZDAu/gvFH/ZU+c0W25tQR8e5hq7WTwiIY2dNxnf+49mRiGI/9yxIwB6f5w==",
"dependencies": {
"@codemirror/lang-html": "^6.0.0",
"@codemirror/lang-javascript": "^6.1.2",
"@codemirror/language": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.3.3"
}
},
"node_modules/@codemirror/lang-cpp": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.2.tgz",
"integrity": "sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/cpp": "^1.0.0"
}
},
"node_modules/@codemirror/lang-css": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.0.2",
"@lezer/css": "^1.1.7"
}
},
"node_modules/@codemirror/lang-go": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-go/-/lang-go-6.0.1.tgz",
"integrity": "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/go": "^1.0.0"
}
},
"node_modules/@codemirror/lang-html": {
"version": "6.4.9",
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/lang-css": "^6.0.0",
"@codemirror/lang-javascript": "^6.0.0",
"@codemirror/language": "^6.4.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0",
"@lezer/css": "^1.1.0",
"@lezer/html": "^1.3.0"
}
},
"node_modules/@codemirror/lang-java": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.1.tgz",
"integrity": "sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/java": "^1.0.0"
}
},
"node_modules/@codemirror/lang-javascript": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.3.tgz",
"integrity": "sha512-8PR3vIWg7pSu7ur8A07pGiYHgy3hHj+mRYRCSG8q+mPIrl0F02rgpGv+DsQTHRTc30rydOsf5PZ7yjKFg2Ackw==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0",
"@lezer/javascript": "^1.0.0"
}
},
"node_modules/@codemirror/lang-json": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/json": "^1.0.0"
}
},
"node_modules/@codemirror/lang-less": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-less/-/lang-less-6.0.2.tgz",
"integrity": "sha512-EYdQTG22V+KUUk8Qq582g7FMnCZeEHsyuOJisHRft/mQ+ZSZ2w51NupvDUHiqtsOy7It5cHLPGfHQLpMh9bqpQ==",
"dependencies": {
"@codemirror/lang-css": "^6.2.0",
"@codemirror/language": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@codemirror/lang-liquid": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-liquid/-/lang-liquid-6.2.2.tgz",
"integrity": "sha512-7Dm841fk37+JQW6j2rI1/uGkJyESrjzyhiIkaLjbbR0U6aFFQvMrJn35WxQreRMADMhzkyVkZM4467OR7GR8nQ==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/lang-html": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.3.1"
}
},
"node_modules/@codemirror/lang-markdown": {
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.3.2.tgz",
"integrity": "sha512-c/5MYinGbFxYl4itE9q/rgN/sMTjOr8XL5OWnC+EaRMLfCbVUmmubTJfdgpfcSS2SCaT7b+Q+xi3l6CgoE+BsA==",
"dependencies": {
"@codemirror/autocomplete": "^6.7.1",
"@codemirror/lang-html": "^6.0.0",
"@codemirror/language": "^6.3.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.2.1",
"@lezer/markdown": "^1.0.0"
}
},
"node_modules/@codemirror/lang-php": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.1.tgz",
"integrity": "sha512-ublojMdw/PNWa7qdN5TMsjmqkNuTBD3k6ndZ4Z0S25SBAiweFGyY68AS3xNcIOlb6DDFDvKlinLQ40vSLqf8xA==",
"dependencies": {
"@codemirror/lang-html": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/php": "^1.0.0"
}
},
"node_modules/@codemirror/lang-python": {
"version": "6.1.7",
"resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.7.tgz",
"integrity": "sha512-mZnFTsL4lW5p9ch8uKNKeRU3xGGxr1QpESLilfON2E3fQzOa/OygEMkaDvERvXDJWJA9U9oN/D4w0ZuUzNO4+g==",
"dependencies": {
"@codemirror/autocomplete": "^6.3.2",
"@codemirror/language": "^6.8.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.2.1",
"@lezer/python": "^1.1.4"
}
},
"node_modules/@codemirror/lang-rust": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.1.tgz",
"integrity": "sha512-344EMWFBzWArHWdZn/NcgkwMvZIWUR1GEBdwG8FEp++6o6vT6KL9V7vGs2ONsKxxFUPXKI0SPcWhyYyl2zPYxQ==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/rust": "^1.0.0"
}
},
"node_modules/@codemirror/lang-sass": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-sass/-/lang-sass-6.0.2.tgz",
"integrity": "sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q==",
"dependencies": {
"@codemirror/lang-css": "^6.2.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.0.2",
"@lezer/sass": "^1.0.0"
}
},
"node_modules/@codemirror/lang-sql": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.8.0.tgz",
"integrity": "sha512-aGLmY4OwGqN3TdSx3h6QeA1NrvaYtF7kkoWR/+W7/JzB0gQtJ+VJxewlnE3+VImhA4WVlhmkJr109PefOOhjLg==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@codemirror/lang-vue": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@codemirror/lang-vue/-/lang-vue-0.1.3.tgz",
"integrity": "sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug==",
"dependencies": {
"@codemirror/lang-html": "^6.0.0",
"@codemirror/lang-javascript": "^6.1.2",
"@codemirror/language": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.3.1"
}
},
"node_modules/@codemirror/lang-wast": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-wast/-/lang-wast-6.0.2.tgz",
"integrity": "sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@codemirror/lang-xml": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz",
"integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.4.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/xml": "^1.0.0"
}
},
"node_modules/@codemirror/lang-yaml": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.2.tgz",
"integrity": "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.2.0",
"@lezer/lr": "^1.0.0",
"@lezer/yaml": "^1.0.0"
}
},
"node_modules/@codemirror/language": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.0.tgz",
"integrity": "sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.23.0",
"@lezer/common": "^1.1.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"style-mod": "^4.0.0"
}
},
"node_modules/@codemirror/language-data": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@codemirror/language-data/-/language-data-6.5.1.tgz",
"integrity": "sha512-0sWxeUSNlBr6OmkqybUTImADFUP0M3P0IiSde4nc24bz/6jIYzqYSgkOSLS+CBIoW1vU8Q9KUWXscBXeoMVC9w==",
"dependencies": {
"@codemirror/lang-angular": "^0.1.0",
"@codemirror/lang-cpp": "^6.0.0",
"@codemirror/lang-css": "^6.0.0",
"@codemirror/lang-go": "^6.0.0",
"@codemirror/lang-html": "^6.0.0",
"@codemirror/lang-java": "^6.0.0",
"@codemirror/lang-javascript": "^6.0.0",
"@codemirror/lang-json": "^6.0.0",
"@codemirror/lang-less": "^6.0.0",
"@codemirror/lang-liquid": "^6.0.0",
"@codemirror/lang-markdown": "^6.0.0",
"@codemirror/lang-php": "^6.0.0",
"@codemirror/lang-python": "^6.0.0",
"@codemirror/lang-rust": "^6.0.0",
"@codemirror/lang-sass": "^6.0.0",
"@codemirror/lang-sql": "^6.0.0",
"@codemirror/lang-vue": "^0.1.1",
"@codemirror/lang-wast": "^6.0.0",
"@codemirror/lang-xml": "^6.0.0",
"@codemirror/lang-yaml": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/legacy-modes": "^6.4.0"
}
},
"node_modules/@codemirror/legacy-modes": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.5.0.tgz",
"integrity": "sha512-dNw5pwTqtR1giYjaJyEajunLqxGavZqV0XRtVZyMJnNOD2HmK9DMUmuCAr6RMFGRJ4l8OeQDjpI/us+R09mQsw==",
"dependencies": {
"@codemirror/language": "^6.0.0"
}
},
"node_modules/@codemirror/lint": {
"version": "6.8.4",
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.4.tgz",
"integrity": "sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.35.0",
"crelt": "^1.0.5"
}
},
"node_modules/@codemirror/search": {
"version": "6.5.10",
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.10.tgz",
"integrity": "sha512-RMdPdmsrUf53pb2VwflKGHEe1XVM07hI7vV2ntgw1dmqhimpatSJKva4VA9h4TLUDOD4EIF02201oZurpnEFsg==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"crelt": "^1.0.5"
}
},
"node_modules/@codemirror/state": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
"dependencies": {
"@marijn/find-cluster-break": "^1.0.0"
}
},
"node_modules/@codemirror/view": {
"version": "6.36.4",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.4.tgz",
"integrity": "sha512-ZQ0V5ovw/miKEXTvjgzRyjnrk9TwriUB1k4R5p7uNnHR9Hus+D1SXHGdJshijEzPFjU25xea/7nhIeSqYFKdbA==",
"dependencies": {
"@codemirror/state": "^6.5.0",
"style-mod": "^4.1.0",
"w3c-keyname": "^2.2.4"
}
},
"node_modules/@ctrl/tinycolor": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
@ -284,6 +639,171 @@
"dev": true,
"license": "MIT"
},
"node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
},
"node_modules/@lezer/cpp": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.3.tgz",
"integrity": "sha512-ykYvuFQKGsRi6IcE+/hCSGUhb/I4WPjd3ELhEblm2wS2cOznDFzO+ubK2c+ioysOnlZ3EduV+MVQFCPzAIoY3w==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/css": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.10.tgz",
"integrity": "sha512-V5/89eDapjeAkWPBpWEfQjZ1Hag3aYUUJOL8213X0dFRuXJ4BXa5NKl9USzOnaLod4AOpmVCkduir2oKwZYZtg==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/go": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.0.tgz",
"integrity": "sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/highlight": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
"dependencies": {
"@lezer/common": "^1.0.0"
}
},
"node_modules/@lezer/html": {
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/java": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.3.tgz",
"integrity": "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/javascript": {
"version": "1.4.21",
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.21.tgz",
"integrity": "sha512-lL+1fcuxWYPURMM/oFZLEDm0XuLN128QPV+VuGtKpeaOGdcl9F2LYC3nh1S9LkPqx9M0mndZFdXCipNAZpzIkQ==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.1.3",
"@lezer/lr": "^1.3.0"
}
},
"node_modules/@lezer/json": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/lr": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
"dependencies": {
"@lezer/common": "^1.0.0"
}
},
"node_modules/@lezer/markdown": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.4.2.tgz",
"integrity": "sha512-iYewCigG/517D0xJPQd7RGaCjZAFwROiH8T9h7OTtz0bRVtkxzFhGBFJ9JGKgBBs4uuo1cvxzyQ5iKhDLMcLUQ==",
"dependencies": {
"@lezer/common": "^1.0.0",
"@lezer/highlight": "^1.0.0"
}
},
"node_modules/@lezer/php": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.2.tgz",
"integrity": "sha512-GN7BnqtGRpFyeoKSEqxvGvhJQiI4zkgmYnDk/JIyc7H7Ifc1tkPnUn/R2R8meH3h/aBf5rzjvU8ZQoyiNDtDrA==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.1.0"
}
},
"node_modules/@lezer/python": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.16.tgz",
"integrity": "sha512-ievIWylIZA5rNgAyHgA06/Y76vMUISKaYL9WrtjU8rCTTEzyZYo2jz9ER2YBdnN6dxCyS7eaK4HJCzamoAMKZw==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/rust": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.2.tgz",
"integrity": "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/sass": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@lezer/sass/-/sass-1.0.7.tgz",
"integrity": "sha512-8HLlOkuX/SMHOggI2DAsXUw38TuURe+3eQ5hiuk9QmYOUyC55B1dYEIMkav5A4IELVaW4e1T4P9WRiI5ka4mdw==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/xml": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz",
"integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/yaml": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.3.tgz",
"integrity": "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.4.0"
}
},
"node_modules/@marijn/find-cluster-break": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="
},
"node_modules/@node-ipc/js-queue": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@node-ipc/js-queue/-/js-queue-2.0.3.tgz",
@ -553,6 +1073,25 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="
},
"node_modules/@types/markdown-it": {
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
"dependencies": {
"@types/linkify-it": "^5",
"@types/mdurl": "^2"
}
},
"node_modules/@types/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="
},
"node_modules/@types/mime": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
@ -675,6 +1214,11 @@
"@types/node": "*"
}
},
"node_modules/@vavt/util": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@vavt/util/-/util-2.1.0.tgz",
"integrity": "sha512-YIfAvArSFVXmWvoF+DEGD0FhkhVNcCtVWWkfYtj76eSrwHh/wuEEFhiEubg1XLNM3tChO8FH8xJCT/hnizjgFQ=="
},
"node_modules/@vue/cli-overlay": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.8.tgz",
@ -1538,6 +2082,11 @@
],
"license": "MIT"
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@ -2179,6 +2728,20 @@
"node": ">=0.10.0"
}
},
"node_modules/codemirror": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/commands": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/search": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -2374,6 +2937,14 @@
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/copy-to-clipboard": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
"integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
"dependencies": {
"toggle-selection": "^1.0.6"
}
},
"node_modules/copy-webpack-plugin": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz",
@ -2434,6 +3005,11 @@
"node": ">=10"
}
},
"node_modules/crelt": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
},
"node_modules/cross-spawn": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz",
@ -2676,6 +3252,11 @@
"node": ">=4"
}
},
"node_modules/cssfilter": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
"integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw=="
},
"node_modules/cssnano": {
"version": "5.1.15",
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz",
@ -4882,6 +5463,14 @@
"dev": true,
"license": "MIT"
},
"node_modules/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
@ -5187,6 +5776,43 @@
"semver": "bin/semver"
}
},
"node_modules/markdown-it": {
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
"linkify-it": "^5.0.0",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/markdown-it-image-figures": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/markdown-it-image-figures/-/markdown-it-image-figures-2.1.1.tgz",
"integrity": "sha512-mwXSQ2nPeVUzCMIE3HlLvjRioopiqyJLNph0pyx38yf9mpqFDhNGnMpAXF9/A2Xv0oiF2cVyg9xwfF0HNAz05g==",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"markdown-it": "*"
}
},
"node_modules/markdown-it-sub": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-2.0.0.tgz",
"integrity": "sha512-iCBKgwCkfQBRg2vApy9vx1C1Tu6D8XYo8NvevI3OlwzBRmiMtsJ2sXupBgEA7PPxiDwNni3qIUkhZ6j5wofDUA=="
},
"node_modules/markdown-it-sup": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-2.0.0.tgz",
"integrity": "sha512-5VgmdKlkBd8sgXuoDoxMpiU+BiEt3I49GItBzzw7Mxq9CxvnhE/k09HFli09zgfFDRixDQDfDxi0mgBCXtaTvA=="
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -5197,6 +5823,34 @@
"node": ">= 0.4"
}
},
"node_modules/md-editor-v3": {
"version": "4.21.3",
"resolved": "https://registry.npmjs.org/md-editor-v3/-/md-editor-v3-4.21.3.tgz",
"integrity": "sha512-9+RCioqFIWSExTsG0jf9T/RTrFhtH8SpRcKVjHeEQSlExAr/zsgYt/M9XUy/nuGx87hgNKDzK0PXp/uOlDumAw==",
"dependencies": {
"@codemirror/lang-markdown": "^6.2.5",
"@codemirror/language-data": "^6.5.1",
"@types/markdown-it": "^14.0.1",
"@vavt/util": "^2.1.0",
"codemirror": "^6.0.1",
"copy-to-clipboard": "^3.3.3",
"lru-cache": "^10.2.0",
"markdown-it": "^14.0.0",
"markdown-it-image-figures": "^2.1.1",
"markdown-it-sub": "^2.0.0",
"markdown-it-sup": "^2.0.0",
"medium-zoom": "^1.1.0",
"xss": "^1.0.15"
},
"peerDependencies": {
"vue": "^3.2.47"
}
},
"node_modules/md-editor-v3/node_modules/lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
},
"node_modules/mdn-data": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
@ -5204,6 +5858,11 @@
"dev": true,
"license": "CC0-1.0"
},
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -5214,6 +5873,11 @@
"node": ">= 0.6"
}
},
"node_modules/medium-zoom": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.1.0.tgz",
"integrity": "sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ=="
},
"node_modules/memfs": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz",
@ -6953,6 +7617,14 @@
"node": ">=6"
}
},
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"engines": {
"node": ">=6"
}
},
"node_modules/qrcode.vue": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/qrcode.vue/-/qrcode.vue-3.6.0.tgz",
@ -7917,6 +8589,11 @@
"node": ">=6"
}
},
"node_modules/style-mod": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
},
"node_modules/stylehacks": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
@ -8215,6 +8892,11 @@
"node": ">=8.0"
}
},
"node_modules/toggle-selection": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@ -8273,6 +8955,11 @@
"node": ">= 0.6"
}
},
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
@ -8543,6 +9230,11 @@
"vue": "^3.0.2"
}
},
"node_modules/w3c-keyname": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
},
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
@ -9067,6 +9759,26 @@
}
}
},
"node_modules/xss": {
"version": "1.0.15",
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz",
"integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==",
"dependencies": {
"commander": "^2.20.3",
"cssfilter": "0.0.10"
},
"bin": {
"xss": "bin/xss"
},
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/xss/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@ -7,6 +7,7 @@
"@vue/cli-service": "^5.0.8",
"ant-design-vue": "^3.2.20",
"axios": "^1.7.9",
"md-editor-v3": "^4.8.3",
"nprogress": "^0.2.0",
"qrcode.vue": "^3.6.0",
"vue": "^3.3.4",

View File

@ -109,6 +109,9 @@
<a-menu-item key="merchant-list">
<router-link to="/merchant/list">商家列表</router-link>
</a-menu-item>
<a-menu-item key="merchant-audit">
<router-link to="/merchant/audit">商家审核</router-link>
</a-menu-item>
<a-menu-item key="merchant-categories">
<router-link to="/merchant/categories">商家分类</router-link>
</a-menu-item>
@ -185,7 +188,7 @@
</template>
<script>
import { ref, defineComponent, onMounted, watch, computed } from 'vue'
import { ref, defineComponent, onMounted, watch, computed, h, provide } from 'vue'
import {
UserOutlined,
HomeOutlined,
@ -221,6 +224,11 @@ export default defineComponent({
TeamOutlined
},
setup() {
// prefixCls
provide('menuContext', { prefixCls: 'ant-menu', inlineIndent: 24, mode: 'inline', theme: 'dark' });
provide('menuItemGroupContext', { prefixCls: 'ant-menu' });
provide('subMenuContext', { prefixCls: 'ant-menu' });
const router = useRouter()
const route = useRoute()
const collapsed = ref(false)
@ -377,6 +385,11 @@ export default defineComponent({
title: '商家列表',
path: '/merchant/list'
},
{
key: 'merchant-audit',
title: '商家审核',
path: '/merchant/audit'
},
{
key: 'merchant-categories',
title: '商家分类',

View File

@ -10,7 +10,6 @@ import {
Input,
Table,
Dropdown,
SubMenu,
Space,
Popconfirm,
Divider,
@ -19,13 +18,20 @@ import {
Select,
InputNumber,
AutoComplete,
Tabs
Tabs,
DatePicker,
Radio,
TimePicker,
Upload,
Image,
message
} from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
const app = createApp(App)
app.use(router)
// 注册需要的组件
app.use(Button)
app.use(Layout)
@ -35,7 +41,6 @@ app.use(Form)
app.use(Input)
app.use(Table)
app.use(Dropdown)
app.use(SubMenu)
app.use(Space)
app.use(Popconfirm)
app.use(Divider)
@ -45,5 +50,19 @@ app.use(Select)
app.use(InputNumber)
app.use(AutoComplete)
app.use(Tabs)
app.use(DatePicker)
app.use(Radio)
app.use(TimePicker)
app.use(Upload)
app.use(Image)
// 手动注册 Menu 相关组件
app.component('ASubMenu', Menu.SubMenu)
app.component('AMenuItem', Menu.Item)
app.component('AMenuItemGroup', Menu.ItemGroup)
app.component('AMenuDivider', Menu.Divider)
// 设置全局属性
app.config.globalProperties.$message = message
app.mount('#app')

View File

@ -104,6 +104,11 @@ const routes = [
component: () => import('@/views/merchant/List.vue'),
meta: { title: '商家列表' }
},
{
path: 'audit',
component: () => import('@/views/merchant/AuditList.vue'),
meta: { title: '商家审核' }
},
{
path: 'categories',
component: () => import('@/views/merchant/CategoryList.vue'),

View File

@ -0,0 +1,869 @@
# 创建一个全新的商家审核列表页面基于List.vue修改但只展示待审核商家
<template>
<page-container>
<div class="merchant-list">
<div class="table-header">
<h1>商家审核</h1>
</div>
<a-table
:columns="columns"
:data-source="tableData"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'create_time'">
{{ formatDateTime(record.create_time) }}
</template>
<template v-if="column.key === 'action'">
<a-space>
<a-button type="primary" @click="handleAudit(record)">审核</a-button>
</a-space>
</template>
</template>
</a-table>
<!-- 审核详情模态框 -->
<a-modal
v-model:visible="auditModalVisible"
title="商家审核详情"
:maskClosable="false"
:keyboard="false"
:width="900"
@cancel="auditModalVisible = false"
:footer="null"
>
<div class="audit-detail" v-if="auditData">
<a-spin :spinning="auditLoading">
<div class="audit-content">
<div class="basic-info-section">
<div class="section-title">基本信息</div>
<a-descriptions bordered :column="2" size="middle" class="merchant-descriptions">
<a-descriptions-item label="商家名称" span="2">
{{ auditData.merchant?.name }}
</a-descriptions-item>
<a-descriptions-item label="品牌图片" span="2">
<div class="brand-image-container">
<img
:src="auditData.merchant?.brand_image_url"
alt="品牌图片"
v-if="auditData.merchant?.brand_image_url"
class="brand-image-preview"
@click="previewImage(auditData.merchant?.brand_image_url, '品牌图片')"
/>
<a-empty v-else description="无品牌图片" />
</div>
</a-descriptions-item>
<a-descriptions-item label="商家分类" span="1">
{{ auditData.merchant?.category_name }}
</a-descriptions-item>
<a-descriptions-item label="商户归属" span="1">
{{ auditData.merchant?.user_nickname ? `${auditData.merchant?.user_nickname} (${auditData.merchant?.user_phone})` : auditData.merchant?.user_phone || '未关联用户' }}
</a-descriptions-item>
<a-descriptions-item label="联系电话" span="1">
{{ auditData.merchant?.phone || '未设置' }}
</a-descriptions-item>
<a-descriptions-item label="营业时间" span="1">
{{ auditData.merchant?.business_hours || '未设置' }}
</a-descriptions-item>
<a-descriptions-item label="买单分佣比例" span="2">
<span class="highlight-text">{{ auditData.merchant?.pay_share_rate || 0 }}%</span>
</a-descriptions-item>
<a-descriptions-item label="创建时间" span="2">
{{ formatDateTime(auditData.merchant?.create_time) }}
</a-descriptions-item>
<a-descriptions-item label="商家地址" span="2">
<div class="address-with-map">
<span>{{ auditData.merchant?.address }}</span>
<a-button
type="link"
size="small"
@click="showMapView"
v-if="auditData.merchant?.longitude && auditData.merchant?.latitude"
>
查看地图位置 <i class="icon-map-marker"></i>
</a-button>
</div>
</a-descriptions-item>
</a-descriptions>
</div>
<div class="auth-section">
<div class="section-title">认证资料</div>
<div class="auth-images">
<div class="auth-image-item">
<div class="auth-image-title">营业执照</div>
<div class="auth-image-container">
<img
:src="auditData.auth?.license_image_url"
alt="营业执照"
v-if="auditData.auth?.license_image_url"
@click="previewImage(auditData.auth?.license_image_url, '营业执照')"
/>
<a-empty v-else description="无营业执照图片" />
</div>
</div>
<div class="auth-image-item">
<div class="auth-image-title">身份证正面</div>
<div class="auth-image-container">
<img
:src="auditData.auth?.id_front_url"
alt="身份证正面"
v-if="auditData.auth?.id_front_url"
@click="previewImage(auditData.auth?.id_front_url, '身份证正面')"
/>
<a-empty v-else description="无身份证正面图片" />
</div>
</div>
<div class="auth-image-item">
<div class="auth-image-title">身份证反面</div>
<div class="auth-image-container">
<img
:src="auditData.auth?.id_back_url"
alt="身份证反面"
v-if="auditData.auth?.id_back_url"
@click="previewImage(auditData.auth?.id_back_url, '身份证反面')"
/>
<a-empty v-else description="无身份证反面图片" />
</div>
</div>
</div>
</div>
<div class="action-buttons">
<a-button type="primary" size="large" @click="handleAuditApprove">审核通过</a-button>
</div>
</div>
</a-spin>
</div>
</a-modal>
<!-- 图片预览模态框 -->
<a-modal
v-model:visible="imagePreviewVisible"
:footer="null"
:width="800"
>
<div class="preview-container">
<img :src="previewImageUrl" :alt="previewImageTitle" class="preview-img" />
</div>
</a-modal>
<!-- 地图预览模态框 -->
<a-modal
v-model:visible="mapViewVisible"
title="商家位置"
:footer="null"
:width="800"
@cancel="closeMapView"
>
<div class="map-container">
<div class="map-address-info">
<div class="map-merchant-name">{{ auditData?.merchant?.name }}</div>
<div class="map-address">{{ auditData?.merchant?.address }}</div>
</div>
<div id="map-container" style="height: 400px; border-radius: 8px; overflow: hidden;"></div>
</div>
</a-modal>
</div>
</page-container>
</template>
<script>
import { defineComponent, ref, onMounted, h, nextTick } from 'vue'
import {
message,
Table,
Button,
Modal,
Spin,
Descriptions,
Empty,
Avatar,
Space
} from 'ant-design-vue'
import dayjs from 'dayjs'
import PageContainer from '@/components/PageContainer.vue'
import request from '@/utils/request'
import { loadAMap, createMap } from '@/utils/amap.js'
export default defineComponent({
components: {
PageContainer,
ATable: Table,
AButton: Button,
AModal: Modal,
ASpin: Spin,
ADescriptions: Descriptions,
ADescriptionsItem: Descriptions.Item,
AEmpty: Empty,
AAvatar: Avatar,
ASpace: Space
},
setup() {
const loading = ref(false)
const tableData = ref([])
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
showTotal: (total) => `${total} 条记录`
})
const columns = [
{
title: '商户归属',
dataIndex: 'user_info',
key: 'user_info',
width: 200,
customRender: ({ record }) => {
if (!record.user_nickname && !record.user_phone) return '-'
return `${record.user_nickname || '未设置昵称'} (${record.user_phone})`
}
},
{
title: '商家分类',
dataIndex: 'category_name',
key: 'category_name',
width: 120,
},
{
title: '品牌图片',
dataIndex: 'brand_image_url',
key: 'brand_image_url',
width: 100,
align: 'center',
customRender: ({ text }) => {
if (!text) return '-'
return h('img', {
src: text,
alt: '品牌图片',
style: {
width: '60px',
height: '60px',
objectFit: 'cover',
borderRadius: '4px'
}
})
}
},
{
title: '商家名称',
dataIndex: 'name',
key: 'name',
width: 200,
},
{
title: '买单分佣比例',
dataIndex: 'pay_share_rate',
key: 'pay_share_rate',
width: 150,
align: 'center',
customRender: ({ text }) => {
return `${text || 0}%`
}
},
{
title: '营业时间',
dataIndex: 'business_hours',
key: 'business_hours',
width: 150,
},
{
title: '联系电话',
dataIndex: 'phone',
key: 'phone',
width: 150,
},
{
title: '创建时间',
dataIndex: 'create_time',
key: 'create_time',
width: 180,
},
{
title: '操作',
key: 'action',
width: 200,
fixed: 'right',
align: 'center'
}
]
//
const formatDateTime = (value) => {
if (!value) return ''
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
}
//
const fetchData = async () => {
try {
loading.value = true
const params = {
skip: (pagination.value.current - 1) * pagination.value.pageSize,
limit: pagination.value.pageSize,
status: 'PENDING' //
}
const res = await request.get('/api/merchant', { params })
if (res.data) {
tableData.value = (res.data.items || []).map(item => ({
...item,
pay_gift_points_rate: Number(item.pay_gift_points_rate || 0),
pay_share_rate: Number(item.pay_share_rate || 0)
}))
pagination.value.total = res.data.total || 0
}
} catch (error) {
} finally {
loading.value = false
}
}
//
const handleTableChange = (pag) => {
pagination.value.current = pag.current
pagination.value.pageSize = pag.pageSize
fetchData()
}
//
const auditModalVisible = ref(false)
const auditLoading = ref(false)
const auditData = ref(null)
const currentRecord = ref(null)
//
const handleAudit = async (record) => {
currentRecord.value = record
auditModalVisible.value = true
await fetchAuditDetail(record.id)
}
//
const fetchAuditDetail = async (merchantId) => {
try {
auditLoading.value = true
const res = await request.get(`/api/merchant/${merchantId}/audit`)
if (res.code === 200 && res.data) {
auditData.value = res.data
} else {
throw new Error(res.message || '获取审核详情失败')
}
} catch (error) {
message.error(error.message || '获取审核详情失败')
} finally {
auditLoading.value = false
}
}
//
const handleAuditApprove = async () => {
try {
auditLoading.value = true
const res = await request.put(`/api/merchant/${currentRecord.value.id}/approve`)
if (res.code === 200) {
message.success('审核通过成功')
auditModalVisible.value = false
fetchData()
} else {
throw new Error(res.message || '操作失败')
}
} catch (error) {
message.error(error.message || '操作失败')
} finally {
auditLoading.value = false
}
}
//
const imagePreviewVisible = ref(false)
const previewImageUrl = ref('')
const previewImageTitle = ref('')
//
const previewImage = (url, title) => {
if (!url) return
previewImageUrl.value = url
previewImageTitle.value = title || '图片预览'
imagePreviewVisible.value = true
}
//
const mapViewVisible = ref(false)
const mapInstance = ref(null)
const mapMarker = ref(null)
//
const showMapView = async () => {
if (!auditData.value?.merchant?.latitude || !auditData.value?.merchant?.longitude) {
message.warning('商家位置信息不完整,无法查看地图')
return
}
mapViewVisible.value = true
// DOM
await nextTick()
try {
await loadAMap()
//
if (!mapInstance.value) {
mapInstance.value = createMap('map-container', {
zoom: 15,
viewMode: '3D'
})
}
const position = [auditData.value.merchant.longitude, auditData.value.merchant.latitude]
mapInstance.value.setCenter(position)
//
if (mapMarker.value) {
mapMarker.value.remove()
}
//
mapMarker.value = new window.AMap.Marker({
position,
map: mapInstance.value,
title: auditData.value.merchant.name
})
//
const infoWindow = new window.AMap.InfoWindow({
content: `
<div class="info-window">
<div class="info-title">${auditData.value.merchant.name}</div>
<div class="info-address">${auditData.value.merchant.address}</div>
<div class="info-phone">电话: ${auditData.value.merchant.phone || '未设置'}</div>
</div>
`,
offset: new window.AMap.Pixel(0, -30)
})
infoWindow.open(mapInstance.value, position)
} catch (error) {
message.error('加载地图失败')
}
}
//
const closeMapView = () => {
mapViewVisible.value = false
}
onMounted(() => {
fetchData()
})
return {
loading,
columns,
tableData,
pagination,
formatDateTime,
handleTableChange,
handleAudit,
auditModalVisible,
auditLoading,
auditData,
handleAuditApprove,
imagePreviewVisible,
previewImageUrl,
previewImageTitle,
previewImage,
mapViewVisible,
showMapView,
closeMapView
}
}
})
</script>
<style scoped>
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.table-header h1 {
margin: 0;
}
:deep(.ant-table-content) {
overflow-x: auto;
}
.audit-detail {
padding: 0;
}
.audit-content {
display: flex;
flex-direction: column;
gap: 24px;
}
.audit-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
border-bottom: 1px solid #f0f0f0;
padding-bottom: 20px;
}
.merchant-brand {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.brand-image {
width: 80px;
height: 80px;
border-radius: 8px;
object-fit: cover;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.merchant-name {
font-size: 18px;
font-weight: 600;
margin-top: 8px;
}
.merchant-info {
display: flex;
flex-direction: column;
gap: 12px;
}
.info-row {
display: flex;
align-items: center;
}
.info-label {
color: rgba(0, 0, 0, 0.65);
margin-right: 8px;
min-width: 100px;
text-align: right;
}
.info-value {
color: rgba(0, 0, 0, 0.85);
font-weight: 500;
}
.address-section {
display: flex;
flex-direction: column;
gap: 12px;
}
.section-title {
font-size: 16px;
font-weight: 600;
color: rgba(0, 0, 0, 0.85);
border-left: 3px solid #1890ff;
padding-left: 10px;
}
.address-content {
background-color: #f9f9f9;
padding: 12px 16px;
border-radius: 4px;
color: rgba(0, 0, 0, 0.85);
}
.auth-section {
display: flex;
flex-direction: column;
gap: 16px;
}
.auth-images {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.auth-image-item {
flex: 1;
min-width: 220px;
display: flex;
flex-direction: column;
gap: 8px;
}
.auth-image-title {
font-weight: 500;
color: rgba(0, 0, 0, 0.65);
}
.auth-image-container {
background-color: #f9f9f9;
border-radius: 4px;
overflow: hidden;
height: 180px;
display: flex;
align-items: center;
justify-content: center;
}
.auth-image-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
cursor: pointer;
transition: transform 0.3s;
}
.auth-image-container img:hover {
transform: scale(1.05);
}
.action-buttons {
margin-top: 16px;
display: flex;
justify-content: center;
padding: 16px 0;
border-top: 1px solid #f0f0f0;
}
.preview-container {
display: flex;
justify-content: center;
align-items: center;
height: 600px;
background-color: rgba(0, 0, 0, 0.02);
}
.preview-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.merchant-basic-info {
display: flex;
gap: 40px;
padding-bottom: 20px;
border-bottom: 1px solid #f0f0f0;
}
.basic-info-left {
width: 180px;
}
.basic-info-right {
flex: 1;
}
.merchant-brand {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.brand-image {
width: 100px;
height: 100px;
border-radius: 8px;
object-fit: cover;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
cursor: pointer;
transition: all 0.3s;
}
.brand-image:hover {
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.merchant-name {
font-size: 18px;
font-weight: 600;
margin-top: 8px;
text-align: center;
word-break: break-all;
}
.info-card {
background-color: #f9f9f9;
border-radius: 8px;
padding: 16px;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.info-row {
display: flex;
flex-direction: column;
gap: 4px;
}
.info-label {
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
display: flex;
align-items: center;
gap: 6px;
}
.info-value {
color: rgba(0, 0, 0, 0.85);
font-weight: 500;
font-size: 16px;
}
.info-value.highlight {
color: #1890ff;
font-size: 20px;
}
.icon-clock, .icon-phone, .icon-percentage, .icon-gift, .icon-map-marker {
display: inline-block;
width: 16px;
height: 16px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.icon-clock::before {
content: "🕒";
}
.icon-phone::before {
content: "📞";
}
.icon-percentage::before {
content: "💰";
}
.icon-gift::before {
content: "🎁";
}
.icon-map-marker::before {
content: "📍";
}
.address-content {
background-color: #f9f9f9;
padding: 12px 16px;
border-radius: 4px;
color: rgba(0, 0, 0, 0.85);
display: flex;
justify-content: space-between;
align-items: center;
}
.address-text {
flex: 1;
}
.map-view-btn {
white-space: nowrap;
display: flex;
align-items: center;
gap: 4px;
}
.map-container {
display: flex;
flex-direction: column;
gap: 16px;
}
.map-address-info {
background-color: #f9f9f9;
padding: 16px;
border-radius: 8px;
}
.map-merchant-name {
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
}
.map-address {
color: rgba(0, 0, 0, 0.85);
margin-bottom: 8px;
}
.map-coordinates {
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
}
.map-view {
border-radius: 8px;
overflow: hidden;
border: 1px solid #f0f0f0;
}
.map-actions {
display: flex;
justify-content: center;
margin-top: 16px;
}
.highlight-text {
color: #1890ff;
font-weight: 600;
font-size: 16px;
}
.merchant-descriptions {
background-color: #fff;
}
.merchant-descriptions :deep(.ant-descriptions-item-label) {
width: 120px;
background-color: #fafafa;
font-weight: 500;
}
.address-with-map {
display: flex;
align-items: center;
gap: 8px;
}
.brand-image-container {
display: flex;
justify-content: center;
}
.brand-image-preview {
height: 80px;
border-radius: 4px;
cursor: pointer;
transition: transform 0.3s;
}
.brand-image-preview:hover {
transform: scale(1.05);
}
</style>

View File

@ -15,17 +15,29 @@
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'location'">
<a @click="showMap(record)">查看位置</a>
</template>
<template v-if="column.key === 'create_time'">
{{ formatDateTime(record.create_time) }}
</template>
<template v-if="column.key === 'action'">
<a-space>
<a-button type="link" @click="handleEdit(record)">修改资料</a-button>
<a-button type="link" @click="showPointsRateModal(record)">修改积分比例</a-button>
</a-space>
<a-dropdown>
<a-button>
操作
<down-outlined />
</a-button>
<template #overlay>
<a-menu>
<a-menu-item key="edit" @click="handleEdit(record)">
<edit-outlined />修改资料
</a-menu-item>
<a-menu-item key="points" @click="showPointsRateModal(record)">
<gift-outlined />修改积分比例
</a-menu-item>
<a-menu-item key="share" @click="showShareRateModal(record)">
<account-book-outlined />设置分润比例
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</template>
</a-table>
@ -169,6 +181,26 @@
/>
</a-input-group>
</a-form-item>
<a-form-item label="产品描述" name="product_detail">
<md-editor
v-model:value="formState.product_detail"
:toolbars="toolbars"
language="zh-CN"
preview-theme="github"
:placeholder="'请输入产品描述'"
/>
</a-form-item>
<a-form-item label="购买须知" name="purchase_note">
<md-editor
v-model:value="formState.purchase_note"
:toolbars="toolbars"
language="zh-CN"
preview-theme="github"
:placeholder="'请输入购买须知'"
/>
</a-form-item>
</a-form>
</a-modal>
@ -313,6 +345,26 @@
/>
</a-input-group>
</a-form-item>
<a-form-item label="产品描述" name="product_detail">
<md-editor
v-model:value="editFormState.product_detail"
:toolbars="toolbars"
language="zh-CN"
preview-theme="github"
:placeholder="'请输入产品描述'"
/>
</a-form-item>
<a-form-item label="购买须知" name="purchase_note">
<md-editor
v-model:value="editFormState.purchase_note"
:toolbars="toolbars"
language="zh-CN"
preview-theme="github"
:placeholder="'请输入购买须知'"
/>
</a-form-item>
</a-form>
</a-modal>
@ -345,6 +397,36 @@
</a-form-item>
</div>
</a-modal>
<!-- 添加分润比例设置模态框 -->
<a-modal
v-model:visible="shareRateModalVisible"
title="设置支付分润比例"
:maskClosable="false"
:keyboard="false"
:width="400"
@ok="handleShareRateSubmit"
@cancel="shareRateModalVisible = false"
>
<div class="points-rate-form">
<a-form-item
label="支付分润比例"
required
extra="订单金额的百分比例如输入60表示分润订单金额的60%"
>
<a-input-number
v-model:value="shareRateValue"
:min="0"
:max="100"
:precision="1"
:step="0.1"
style="width: 100%"
addonAfter="%"
placeholder="请输入0-100之间的数值"
/>
</a-form-item>
</div>
</a-modal>
</div>
</page-container>
</template>
@ -356,15 +438,22 @@ import dayjs from 'dayjs'
import PageContainer from '@/components/PageContainer.vue'
import { loadAMap, createMap, createAutoComplete, createGeocoder } from '@/utils/amap.js'
import request from '@/utils/request'
import { PlusOutlined, SearchOutlined } from '@ant-design/icons-vue'
import { PlusOutlined, SearchOutlined, EditOutlined, DownOutlined, GiftOutlined, AccountBookOutlined } from '@ant-design/icons-vue'
import { MdEditor } from 'md-editor-v3'
import 'md-editor-v3/lib/style.css'
export default defineComponent({
components: {
PageContainer,
PlusOutlined,
SearchOutlined,
EditOutlined,
DownOutlined,
GiftOutlined,
AccountBookOutlined,
AUpload: Upload,
AModal: Modal
AModal: Modal,
MdEditor
},
setup() {
const loading = ref(false)
@ -373,6 +462,27 @@ export default defineComponent({
const currentMap = ref(null)
const currentMarker = ref(null)
// Markdown
const toolbars = [
'bold',
'underline',
'italic',
'strikeThrough',
'title',
'sub',
'sup',
'quote',
'unorderedList',
'orderedList',
'codeRow',
'code',
'link',
'image',
'table',
'preview',
'fullscreen'
]
const pagination = ref({
current: 1,
pageSize: 10,
@ -441,25 +551,22 @@ export default defineComponent({
return `${text || 0}%`
}
},
{
title: '买单分佣比例',
dataIndex: 'pay_share_rate',
key: 'pay_share_rate',
width: 150,
align: 'center',
customRender: ({ text }) => {
return `${text || 0}%`
}
},
{
title: '营业时间',
dataIndex: 'business_hours',
key: 'business_hours',
width: 150,
},
{
title: '地址',
dataIndex: 'address',
key: 'address',
ellipsis: true,
width: 300,
},
{
title: '位置',
key: 'location',
width: 100,
align: 'center',
},
{
title: '联系电话',
dataIndex: 'phone',
@ -500,7 +607,8 @@ export default defineComponent({
if (res.data) {
tableData.value = (res.data.items || []).map(item => ({
...item,
pay_gift_points_rate: Number(item.pay_gift_points_rate || 0)
pay_gift_points_rate: Number(item.pay_gift_points_rate || 0),
pay_share_rate: Number(item.pay_share_rate || 0)
}))
pagination.value.total = res.data.total || 0
}
@ -580,6 +688,8 @@ export default defineComponent({
latitude: null,
phone: '',
brand_image_url: '',
product_detail: '',
purchase_note: '',
})
const rules = {
@ -590,6 +700,8 @@ export default defineComponent({
business_hours: [{ required: true, message: '请输入营业时间' }],
address: [{ required: true, message: '请输入详细地址' }],
phone: [{ required: true, message: '请输入联系电话' }],
product_detail: [{ required: false, message: '请输入产品描述' }],
purchase_note: [{ required: false, message: '请输入购买须知' }],
}
//
@ -731,12 +843,20 @@ export default defineComponent({
formRef.value.validate().then(async () => {
try {
confirmLoading.value = true
await request.post('/api/merchant', formState.value)
//
const postData = {
...formState.value,
product_detail: formState.value.product_detail || '',
purchase_note: formState.value.purchase_note || ''
}
await request.post('/api/merchant', postData)
message.success('添加成功')
addModalVisible.value = false
fetchData()
} catch (error) {
message.error(error.message || '添加失败')
} finally {
confirmLoading.value = false
}
@ -756,6 +876,8 @@ export default defineComponent({
latitude: null,
phone: '',
brand_image_url: '',
product_detail: '',
purchase_note: '',
}
searchAddress.value = ''
searchOptions.value = []
@ -811,6 +933,8 @@ export default defineComponent({
latitude: null,
phone: '',
brand_image_url: '',
product_detail: '',
purchase_note: '',
})
const editSearchAddress = ref('')
const editMap = ref(null)
@ -822,7 +946,9 @@ export default defineComponent({
currentEditId.value = record.id
editFormState.value = {
...record,
user_id: record.user_id
user_id: record.user_id,
product_detail: record.product_detail || '',
purchase_note: record.purchase_note || ''
}
//
@ -932,10 +1058,12 @@ export default defineComponent({
try {
editLoading.value = true
// user_id
// user_id
const updateData = {
...editFormState.value,
user_id: editFormState.value.user_id
user_id: editFormState.value.user_id,
product_detail: editFormState.value.product_detail || '',
purchase_note: editFormState.value.purchase_note || ''
}
const res = await request.put(`/api/merchant/${currentEditId.value}`, updateData)
@ -948,7 +1076,6 @@ export default defineComponent({
throw new Error(res.message || '修改失败')
}
} catch (error) {
message.error(error.message || '修改失败')
} finally {
editLoading.value = false
@ -969,6 +1096,8 @@ export default defineComponent({
latitude: null,
phone: '',
brand_image_url: '',
product_detail: '',
purchase_note: '',
}
editSearchAddress.value = ''
userOptions.value = []
@ -1117,6 +1246,39 @@ export default defineComponent({
}
}
//
const shareRateModalVisible = ref(false)
const shareRateValue = ref(0)
const showShareRateModal = (record) => {
currentRecord.value = record
shareRateValue.value = Number(record.pay_share_rate || 0)
shareRateModalVisible.value = true
}
const handleShareRateSubmit = async () => {
try {
if (shareRateValue.value < 0 || shareRateValue.value > 100) {
message.error('分润比例必须在0-100之间')
return
}
const res = await request.put(`/api/merchant/${currentRecord.value.id}`, {
pay_share_rate: shareRateValue.value
})
if (res.code === 200) {
message.success('设置成功')
shareRateModalVisible.value = false
fetchData()
} else {
throw new Error(res.message || '设置失败')
}
} catch (error) {
message.error(error.message || '设置失败')
}
}
onMounted(() => {
fetchData()
})
@ -1169,7 +1331,12 @@ export default defineComponent({
pointsRateModalVisible,
pointsRateValue,
showPointsRateModal,
handlePointsRateSubmit
handlePointsRateSubmit,
shareRateModalVisible,
shareRateValue,
showShareRateModal,
handleShareRateSubmit,
toolbars
}
}
})
@ -1386,4 +1553,52 @@ export default defineComponent({
.points-rate-form :deep(.ant-input-number) {
width: 100% !important;
}
/* Markdown 编辑器样式 */
:deep(.md-editor) {
height: 300px !important;
margin-bottom: 24px;
}
:deep(.md-editor-content) {
height: 300px !important;
}
:deep(.ant-modal-body) {
padding: 24px;
}
:deep(.md-editor-toolbar) {
border-radius: 2px 2px 0 0 !important;
}
:deep(.md-editor-input, .md-editor-preview) {
border-radius: 0 0 2px 2px !important;
}
:deep(.md-editor-preview-wrapper) {
padding: 8px 16px !important;
}
:deep(.ant-modal .ant-modal-content) {
background: #fff;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
}
:deep(.md-editor) {
width: 100% !important;
}
:deep(.md-editor-input) {
padding: 12px !important;
}
/* 编辑和添加模态框中的内容样式 */
:deep(.ant-modal-body:has(.ant-form)) {
padding: 24px;
max-height: 80vh;
overflow-y: auto;
}
</style>

View File

@ -37,7 +37,6 @@
:loading="loading"
@change="handleTableChange"
row-key="id"
:scroll="{ x: 1500 }"
>
<template #bodyCell="{ column, text, record }">
<!-- 图片列 -->
@ -88,7 +87,7 @@
v-model:visible="addModalVisible"
title="添加商品"
:confirmLoading="confirmLoading"
width="600px"
width="900px"
@cancel="handleCancel"
>
<template #footer>
@ -104,22 +103,11 @@
ref="formRef"
:model="formState"
:rules="rules"
:label-col="{ span: 6 }"
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
>
<a-form-item label="所属商家" name="merchant_id" required>
<a-select
v-model:value="formState.merchant_id"
placeholder="请选择商家"
:options="merchantOptions"
:field-names="{ label: 'name', value: 'id' }"
/>
</a-form-item>
<a-form-item label="商品名称" name="name" required>
<a-input v-model:value="formState.name" placeholder="请输入商品名称" />
</a-form-item>
<div class="two-column-form">
<div class="form-column">
<a-form-item label="商品图片" name="image_url" required>
<div class="upload-wrapper">
<div v-if="formState.image_url" class="image-preview">
@ -143,6 +131,19 @@
</div>
</a-form-item>
<a-form-item label="所属商家" name="merchant_id" required>
<a-select
v-model:value="formState.merchant_id"
placeholder="请选择商家"
:options="merchantOptions"
:field-names="{ label: 'name', value: 'id' }"
/>
</a-form-item>
<a-form-item label="商品名称" name="name" required>
<a-input v-model:value="formState.name" placeholder="请输入商品名称" />
</a-form-item>
<a-form-item label="商品原价" name="product_price" required>
<a-input-number
v-model:value="formState.product_price"
@ -173,6 +174,52 @@
/>
</a-form-item>
<a-form-item label="库存设置" name="qty" required>
<a-input-number
v-model:value="formState.qty"
:min="0"
style="width: 100%"
placeholder="请输入库存数量"
/>
</a-form-item>
</div>
<div class="form-column">
<a-form-item
label="赠送积分比例"
name="gift_points_rate"
required
>
<a-input-number
v-model:value="formState.gift_points_rate"
:min="0"
:max="100"
:precision="1"
:step="0.1"
style="width: 100%"
addonAfter="%"
placeholder="请输入0-100之间的数值"
/>
<div class="form-item-help">消费金额的百分比例如10表示赠送10%作为积分</div>
</a-form-item>
<a-form-item
label="促销文本"
name="promotion_text"
>
<a-input
v-model:value="formState.promotion_text"
placeholder="例如:新人三折"
:maxLength="5"
show-count
/>
<div class="form-item-help">显示在商品下方的促销文本限5个字以内</div>
</a-form-item>
<a-form-item label="标签" name="tags">
<a-input v-model:value="formState.tags" placeholder="多个标签用逗号分隔" />
</a-form-item>
<a-form-item label="限购次数" name="purchase_limit">
<a-input-number
v-model:value="formState.purchase_limit"
@ -185,40 +232,69 @@
<div class="form-item-help">0 次表示不限购</div>
</a-form-item>
<a-form-item label="标签" name="tags">
<a-input v-model:value="formState.tags" placeholder="多个标签用逗号分隔" />
<a-form-item label="配送方式" name="delivery_type" required>
<a-radio-group v-model:value="formState.delivery_type">
<a-radio value="DELIVERY">配送到家</a-radio>
<a-radio value="PICKUP">自提</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
label="促销文本"
name="promotion_text"
extra="显示在商品下方的促销文本限5个字以内"
v-if="formState.delivery_type === 'PICKUP'"
label="自提点"
name="pickup_place"
required
>
<a-input
v-model:value="formState.promotion_text"
placeholder="例如:新人三折"
:maxLength="5"
show-count
v-model:value="formState.pickup_place"
placeholder="请输入自提点地址"
/>
</a-form-item>
<a-form-item
label="赠送积分比例"
name="gift_points_rate"
v-if="formState.delivery_type === 'PICKUP'"
label="自提时间"
name="pickup_time"
required
extra="消费金额的百分比例如输入10表示赠送消费金额的10%作为积分"
>
<a-input-number
v-model:value="formState.gift_points_rate"
:min="0"
:max="100"
:precision="1"
:step="0.1"
<a-date-picker
v-model:value="pickupDateTime"
type="date"
show-time
format="YYYY-MM-DD HH:mm"
placeholder="请选择自提日期和时间"
style="width: 100%"
addonAfter="%"
placeholder="请输入0-100之间的数值"
@change="updatePickupTime"
:disabled-date="disabledDate"
:show-time="{ format: 'HH:mm', minuteStep: 10 }"
/>
<div class="form-item-help">请选择自提的日期和时间</div>
</a-form-item>
<a-form-item label="配送时间类型" name="delivery_time_type" required>
<a-radio-group v-model:value="formState.delivery_time_type">
<a-radio value="IMMEDIATE">及时送</a-radio>
<a-radio value="SCHEDULED">定时送</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
v-if="formState.delivery_time_type === 'SCHEDULED'"
label="送货时间"
name="delivery_date"
required
>
<a-date-picker
v-model:value="formState.delivery_date"
:disabled-date="disabledDate"
format="YYYY-MM-DD"
valueFormat="YYYY-MM-DD"
style="width: 100%"
placeholder="请选择送货日期"
/>
</a-form-item>
</div>
</div>
</a-form>
</a-modal>
@ -227,7 +303,7 @@
v-model:visible="editModalVisible"
title="修改商品"
:confirmLoading="editLoading"
width="600px"
width="900px"
@cancel="handleEditCancel"
>
<template #footer>
@ -243,13 +319,11 @@
ref="editFormRef"
:model="editFormState"
:rules="rules"
:label-col="{ span: 6 }"
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
>
<a-form-item label="商品名称" name="name" required>
<a-input v-model:value="editFormState.name" placeholder="请输入商品名称" />
</a-form-item>
<div class="two-column-form">
<div class="form-column">
<a-form-item label="商品图片" name="image_url" required>
<div class="upload-wrapper">
<div v-if="editFormState.image_url" class="image-preview">
@ -273,6 +347,10 @@
</div>
</a-form-item>
<a-form-item label="商品名称" name="name" required>
<a-input v-model:value="editFormState.name" placeholder="请输入商品名称" />
</a-form-item>
<a-form-item label="商品原价" name="product_price" required>
<a-input-number
v-model:value="editFormState.product_price"
@ -303,6 +381,52 @@
/>
</a-form-item>
<a-form-item label="库存设置" name="qty" required>
<a-input-number
v-model:value="editFormState.qty"
:min="0"
style="width: 100%"
placeholder="请输入库存数量"
/>
</a-form-item>
</div>
<div class="form-column">
<a-form-item
label="赠送积分比例"
name="gift_points_rate"
required
>
<a-input-number
v-model:value="editFormState.gift_points_rate"
:min="0"
:max="100"
:precision="1"
:step="0.1"
style="width: 100%"
addonAfter="%"
placeholder="请输入0-100之间的数值"
/>
<div class="form-item-help">消费金额的百分比例如10表示赠送10%作为积分</div>
</a-form-item>
<a-form-item
label="促销文本"
name="promotion_text"
>
<a-input
v-model:value="editFormState.promotion_text"
placeholder="例如:新人三折"
:maxLength="5"
show-count
/>
<div class="form-item-help">显示在商品下方的促销文本限5个字以内</div>
</a-form-item>
<a-form-item label="标签" name="tags">
<a-input v-model:value="editFormState.tags" placeholder="多个标签用逗号分隔" />
</a-form-item>
<a-form-item label="限购次数" name="purchase_limit">
<a-input-number
v-model:value="editFormState.purchase_limit"
@ -315,40 +439,69 @@
<div class="form-item-help">0 次表示不限购</div>
</a-form-item>
<a-form-item label="标签" name="tags">
<a-input v-model:value="editFormState.tags" placeholder="多个标签用逗号分隔" />
<a-form-item label="配送方式" name="delivery_type" required>
<a-radio-group v-model:value="editFormState.delivery_type">
<a-radio value="DELIVERY">配送到家</a-radio>
<a-radio value="PICKUP">自提</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
label="促销文本"
name="promotion_text"
extra="显示在商品下方的促销文本限5个字以内"
v-if="editFormState.delivery_type === 'PICKUP'"
label="自提点"
name="pickup_place"
required
>
<a-input
v-model:value="editFormState.promotion_text"
placeholder="例如:新人三折"
:maxLength="5"
show-count
v-model:value="editFormState.pickup_place"
placeholder="请输入自提点地址"
/>
</a-form-item>
<a-form-item
label="赠送积分比例"
name="gift_points_rate"
v-if="editFormState.delivery_type === 'PICKUP'"
label="自提时间"
name="pickup_time"
required
extra="消费金额的百分比例如输入10表示赠送消费金额的10%作为积分"
>
<a-input-number
v-model:value="editFormState.gift_points_rate"
:min="0"
:max="100"
:precision="1"
:step="0.1"
<a-date-picker
v-model:value="editPickupDateTime"
type="date"
show-time
format="YYYY-MM-DD HH:mm"
placeholder="请选择自提日期和时间"
style="width: 100%"
addonAfter="%"
placeholder="请输入0-100之间的数值"
@change="updateEditPickupTime"
:disabled-date="disabledDate"
:show-time="{ format: 'HH:mm', minuteStep: 10 }"
/>
<div class="form-item-help">请选择自提的日期和时间</div>
</a-form-item>
<a-form-item label="配送时间类型" name="delivery_time_type" required>
<a-radio-group v-model:value="editFormState.delivery_time_type">
<a-radio value="IMMEDIATE">及时送</a-radio>
<a-radio value="SCHEDULED">定时送</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
v-if="editFormState.delivery_time_type === 'SCHEDULED'"
label="送货时间"
name="delivery_date"
required
>
<a-date-picker
v-model:value="editFormState.delivery_date"
:disabled-date="disabledDate"
format="YYYY-MM-DD"
valueFormat="YYYY-MM-DD"
style="width: 100%"
placeholder="请选择送货日期"
/>
</a-form-item>
</div>
</div>
</a-form>
</a-modal>
</div>
@ -356,12 +509,17 @@
</template>
<script>
import { defineComponent, ref, onMounted, h } from 'vue'
import { message, Upload, InputNumber, Tag } from 'ant-design-vue'
import { defineComponent, ref, onMounted, h, computed, watch } from 'vue'
import { message, Upload, InputNumber, Tag, Radio, DatePicker, Row, Col, TimePicker, Space, Input } from 'ant-design-vue'
import { UploadOutlined } from '@ant-design/icons-vue'
import PageContainer from '@/components/PageContainer.vue'
import { getMerchantProducts, updateProductStatus } from '@/api/merchant'
import request from '@/utils/request'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
// dayjs
dayjs.locale('zh-cn')
export default defineComponent({
components: {
@ -369,7 +527,15 @@ export default defineComponent({
UploadOutlined,
AUpload: Upload,
AInputNumber: InputNumber,
ATag: Tag
ATag: Tag,
ARadio: Radio,
ARadioGroup: Radio.Group,
ADatePicker: DatePicker,
ATimePicker: TimePicker,
ASpace: Space,
ARow: Row,
ACol: Col,
AInput: Input
},
setup() {
const loading = ref(false)
@ -388,70 +554,71 @@ export default defineComponent({
showTotal: (total) => `${total} 条记录`
})
//
const addModalVisible = ref(false)
const confirmLoading = ref(false)
const formRef = ref(null)
const formState = ref({
merchant_id: undefined,
name: '',
image_url: '',
product_price: null,
sale_price: null,
settlement_amount: null,
purchase_limit: 0,
tags: '',
gift_points_rate: 0,
promotion_text: '',
qty: 0,
delivery_type: 'DELIVERY',
pickup_place: '',
pickup_time: '',
delivery_time_type: 'IMMEDIATE',
delivery_date: null
})
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
width: 80,
width: 60,
align: 'center'
},
{
title: '商品图片',
dataIndex: 'image_url',
key: 'image_url',
width: 100,
width: 80,
align: 'center'
},
{
title: '所属商家',
dataIndex: 'merchant_name',
key: 'merchant_name',
width: 160,
width: '15%',
ellipsis: true
},
{
title: '商品名称',
dataIndex: 'name',
key: 'name',
width: 200,
},
{
title: '赠送积分比例',
dataIndex: 'gift_points_rate',
key: 'gift_points_rate',
width: 150,
align: 'center',
customRender: ({ text }) => {
return `${text || 0}%`
}
},
{
title: '商品原价',
dataIndex: 'product_price',
key: 'product_price',
width: 100,
align: 'right'
width: '25%',
ellipsis: true
},
{
title: '销售价格',
dataIndex: 'sale_price',
key: 'sale_price',
width: 100,
align: 'right'
},
{
title: '结算价格',
dataIndex: 'settlement_amount',
key: 'settlement_amount',
width: 100,
width: '10%',
align: 'right'
},
{
title: '限购',
dataIndex: 'purchase_limit',
key: 'purchase_limit',
width: 100,
width: '10%',
align: 'center',
customRender: ({ text }) => {
return h(
@ -463,25 +630,18 @@ export default defineComponent({
)
}
},
{
title: '标签',
dataIndex: 'tags',
key: 'tags',
width: 120
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
width: '10%',
align: 'center'
},
{
title: '操作',
key: 'action',
width: 100,
align: 'center',
fixed: 'right'
width: '15%',
align: 'center'
}
]
@ -565,10 +725,56 @@ export default defineComponent({
purchase_limit: 0,
tags: '',
gift_points_rate: 0,
promotion_text: ''
promotion_text: '',
qty: 0,
delivery_type: 'DELIVERY',
pickup_place: '',
pickup_time: '',
delivery_time_type: 'IMMEDIATE',
delivery_date: null
})
//
//
const pickupDateTime = ref(null);
//
const editPickupDateTime = ref(null);
//
const updatePickupTime = () => {
if (pickupDateTime.value) {
formState.value.pickup_time = dayjs(pickupDateTime.value).format('YYYY-MM-DD HH:mm');
} else {
formState.value.pickup_time = '';
}
};
//
const updateEditPickupTime = () => {
if (editPickupDateTime.value) {
editFormState.value.pickup_time = dayjs(editPickupDateTime.value).format('YYYY-MM-DD HH:mm');
} else {
editFormState.value.pickup_time = '';
}
};
// delivery_type
watch(() => formState.value.delivery_type, (newType) => {
if (newType !== 'PICKUP') {
pickupDateTime.value = null;
formState.value.pickup_time = '';
}
});
// delivery_type
watch(() => editFormState.value.delivery_type, (newType) => {
if (newType !== 'PICKUP') {
editPickupDateTime.value = null;
editFormState.value.pickup_time = '';
}
});
// pickup_time
const handleEdit = (record) => {
currentEditId.value = record.id
editFormState.value = {
@ -580,8 +786,27 @@ export default defineComponent({
purchase_limit: record.purchase_limit,
tags: record.tags,
gift_points_rate: record.gift_points_rate,
promotion_text: record.promotion_text
promotion_text: record.promotion_text,
qty: record.qty || 0,
delivery_type: record.delivery_type || 'DELIVERY',
pickup_place: record.pickup_place || '',
pickup_time: record.pickup_time || '',
delivery_time_type: record.delivery_time_type || 'IMMEDIATE',
delivery_date: record.delivery_date || null
}
// pickup_time
if (record.pickup_time) {
try {
editPickupDateTime.value = dayjs(record.pickup_time);
} catch (e) {
console.error('解析自提时间失败:', e);
editPickupDateTime.value = null;
}
} else {
editPickupDateTime.value = null;
}
editModalVisible.value = true
}
@ -621,7 +846,13 @@ export default defineComponent({
editFormRef.value.validate().then(async () => {
try {
editLoading.value = true
const res = await request.put(`/api/merchant/product/${currentEditId.value}`, editFormState.value)
// -
const formData = { ...editFormState.value };
if (formData.delivery_date) {
formData.delivery_date = dayjs(formData.delivery_date).format('YYYY-MM-DD');
}
const res = await request.put(`/api/merchant/product/${currentEditId.value}`, formData)
if (res.code === 200) {
message.success('修改成功')
editModalVisible.value = false
@ -650,28 +881,23 @@ export default defineComponent({
purchase_limit: 0,
tags: '',
gift_points_rate: 0,
promotion_text: ''
promotion_text: '',
qty: 0,
delivery_type: 'DELIVERY',
pickup_place: '',
pickup_time: '',
delivery_time_type: 'IMMEDIATE',
delivery_date: null
}
editPickupDateTime.value = null;
editModalVisible.value = false
}
//
const addModalVisible = ref(false)
const confirmLoading = ref(false)
const formRef = ref(null)
const formState = ref({
merchant_id: undefined,
name: '',
image_url: '',
product_price: null,
sale_price: null,
settlement_amount: null,
purchase_limit: 0,
tags: '',
gift_points_rate: 0,
promotion_text: ''
})
//
const disabledDate = (current) => {
//
return current && current < Date.now() - 8.64e7; // 8.64e7
};
const rules = {
merchant_id: [{ required: true, message: '请选择所属商家' }],
@ -684,7 +910,43 @@ export default defineComponent({
{ required: true, message: '请输入赠送积分比例' },
{ type: 'number', message: '请输入有效的数字' },
{ type: 'number', min: 0, max: 100, message: '比例必须在0-100之间' }
]
],
qty: [{ required: true, message: '请输入库存数量' }],
delivery_type: [{ required: true, message: '请选择配送方式' }],
pickup_place: [{
required: true,
message: '请输入自提点地址',
trigger: 'change',
validator: (rule, value) => {
if (formState.value.delivery_type === 'PICKUP' && (!value || value.trim() === '')) {
return Promise.reject('请输入自提点地址');
}
return Promise.resolve();
}
}],
pickup_time: [{
required: true,
message: '请输入自提时间',
trigger: 'change',
validator: (rule, value) => {
if (formState.value.delivery_type === 'PICKUP' && (!value || value.trim() === '')) {
return Promise.reject('请输入自提时间');
}
return Promise.resolve();
}
}],
delivery_time_type: [{ required: true, message: '请选择配送时间类型' }],
delivery_date: [{
required: true,
message: '请选择送货日期',
trigger: 'change',
validator: (rule, value) => {
if (formState.value.delivery_time_type === 'SCHEDULED' && !value) {
return Promise.reject('请选择送货日期');
}
return Promise.resolve();
}
}]
}
//
@ -728,7 +990,13 @@ export default defineComponent({
formRef.value.validate().then(async () => {
try {
confirmLoading.value = true
const res = await request.post('/api/merchant/product', formState.value)
// -
const formData = { ...formState.value };
if (formData.delivery_date) {
formData.delivery_date = dayjs(formData.delivery_date).format('YYYY-MM-DD');
}
const res = await request.post('/api/merchant/product', formData)
if (res.code === 200) {
message.success('添加成功')
addModalVisible.value = false
@ -758,8 +1026,15 @@ export default defineComponent({
purchase_limit: 0,
tags: '',
gift_points_rate: 0,
promotion_text: ''
promotion_text: '',
qty: 0,
delivery_type: 'DELIVERY',
pickup_place: '',
pickup_time: '',
delivery_time_type: 'IMMEDIATE',
delivery_date: null
}
pickupDateTime.value = null;
addModalVisible.value = false
}
@ -844,7 +1119,12 @@ export default defineComponent({
handleEditCancel,
getStatusText,
getStatusColor,
handleToggleStatus
handleToggleStatus,
disabledDate,
pickupDateTime,
updatePickupTime,
editPickupDateTime,
updateEditPickupTime,
}
}
})
@ -931,24 +1211,41 @@ export default defineComponent({
}
.table-container {
overflow-x: auto;
background: #fff;
border-radius: 2px;
padding: 0;
width: 100%;
max-width: 100%;
overflow: hidden;
}
:deep(.ant-table-wrapper) {
width: 100%;
max-width: 100%;
overflow: hidden;
}
:deep(.ant-table) {
overflow-x: auto;
width: 100%;
table-layout: fixed;
}
:deep(.ant-table-container) {
overflow-x: hidden !important;
}
:deep(.ant-table-content) {
overflow-x: hidden !important;
}
:deep(.ant-table-body) {
overflow-x: auto !important;
overflow-x: hidden !important;
}
:deep(.ant-table-cell) {
white-space: nowrap;
white-space: normal;
word-break: break-word;
overflow: hidden;
}
:deep(.ant-table-cell-ellipsis) {
@ -957,12 +1254,20 @@ export default defineComponent({
text-overflow: ellipsis;
}
:deep(.ant-input-number-group-addon) {
padding: 0 8px;
color: rgba(0, 0, 0, 0.45);
background-color: #fafafa;
border: 1px solid #d9d9d9;
border-radius: 0 2px 2px 0;
:deep(.ant-table-thead > tr > th) {
word-break: break-word;
white-space: normal;
}
:deep(.ant-btn-link) {
padding: 2px 4px;
height: auto;
}
:deep(.ant-space-compact) {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.form-item-help {
@ -991,4 +1296,26 @@ export default defineComponent({
padding: 3px 12px;
border-radius: 12px;
}
.two-column-form {
display: flex;
flex-wrap: wrap;
margin: 0 -8px;
}
.form-column {
flex: 1;
min-width: 300px;
padding: 0 8px;
}
.time-range-wrapper {
display: flex;
align-items: center;
}
.time-separator {
margin: 0 8px;
color: rgba(0, 0, 0, 0.45);
}
</style>