上传代码
24
CampusExpressDelivery/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
5
CampusExpressDelivery/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Vue 3 + TypeScript + Vite
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||||
|
|
||||||
|
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
||||||
27
CampusExpressDelivery/SSL/xiaokuaisong.shop.key
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEA7gB1IUC1Utw3ghZ3Do2VJaBC+vAJUapVPCm4UuBZBvjziMnU
|
||||||
|
feqhe1OPAkwUC1CDtuh5+xacknsheY6CrdfOV5qkMqCvg4opavcCWuj9d5wppO1U
|
||||||
|
oBjsbYNUslYzwq2F3X0/N1sFUOQM56V69fIY+Kedos6FHsZD/ErX7yhDBY4H4Se2
|
||||||
|
Q5NQjL12eWVys3Jn07ATTTAfVbsewJAxeMh58j51kVU0XhijemuibvtgiCSKMa4J
|
||||||
|
TUM2+tldxC9Xfb4Et3xFTWdAJnp945oqWAzoDa9YszNGYJrs3TFJKsCxuXe8wBBT
|
||||||
|
4iRLb+hcyVm8Wekax04HmJhl1NZhT+pg7mHnoQIDAQABAoIBAAQrkEHVdrvhgYw7
|
||||||
|
KSnBTbPFoqjPkgU7HCBYTYtPtKWicO90lF9isCLHXngMhdUjK3Sl7wW5EiQfqdDt
|
||||||
|
wCDMSUh4DGCZ98tQ7Vv7QSB/SLoq24CxGyCNQT7DvGUdzS1AAbqFWFlHpDCkN0zr
|
||||||
|
hYuXyuvX8YNV1aep8wzhkZYmXSLErztMiFUvUYscIqQLkuVO8c0ydiA1ALPhvtB2
|
||||||
|
Sv6PrEHeXMvi8ESTh/BMxrCHZZrDDodCMh0goY212UCAhBY/CG2z15s1GmgjdENt
|
||||||
|
Fh88Ic5ZUTLq5BRM3tDRlErb/6/9lQLPxpfExPKC4eOyKHMpGvvPrzQUEWaUSlu2
|
||||||
|
rzI6uQECgYEA/32Q7mYmvkIoAUmNPi7f8G65NKTVi6eUhkrbVKUksx78dqLg2Ay1
|
||||||
|
156YJwA+VFdwnw3OkMlJYIhXXF7wQ6MvFB21wXkEkMQj/J/l3f/LoeVrR+Md2lyF
|
||||||
|
M3P04zWkQoCRdTz9L3U08szlk7bj4RJxbLYxJ/0jJcO5H8afN1BkOSECgYEA7nn2
|
||||||
|
h7jwvEZkTN1sAsYROQKssxBhZYQ4+M4wJ+QdGB4t6KNbO2PH+l1U8Mg2yFq++QRq
|
||||||
|
uP9Q+qr89oTUYggmXzGseV5SeArMA5VN7py5Jg8L8eJGVEXALLXaC3ywTNY33A2C
|
||||||
|
ff55HT7TRDoI638T4k7iYJ1VkfaDsexEgi8HXoECgYBK2H8fx98rt3e+wMxW3iaO
|
||||||
|
afFpwawpaGNzX/SW/HYe30H4g0i5IigXTYenTUP1M1Rz0/iio8USOX7WOZ3LQr/k
|
||||||
|
9bssPYaf3kXomPMfMPN3rxzZh2hUcuw2oY6pDSrcrItwO/iz8XMceff7aQWjBuMh
|
||||||
|
hNIrs9WbF5Zg/6/e5Xcm4QKBgCAM9D05deFX9JMAD0wwIpBu85b9VJm4M4/85iv2
|
||||||
|
VJKxO6pQiippNq9Ha+sQfYxf5drB5TYH2nJWGLlpEMI8JiwVGQEW1C6eBN1Wa6ru
|
||||||
|
FVQwIYLYzmr1FObtaeixUWCCSe+hQTB9yvlLQEmjIx/DbIC16WbivmVnpDt9bZex
|
||||||
|
imQBAoGARrA+XSwSytsdeM1JTIBwOhS8IprraxfVqhaqg7zneypy54Q3V9+inVeK
|
||||||
|
rvVmEazUVtZsTg/J3uKxHv+LX+mFdwAV8lDElz/p1K1stMfsSUnNKLLDmRjrN586
|
||||||
|
RBcp36sTnMVYikffNqxfowzymmvrJAKOny3sovZICzPkgzoPTm8=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
62
CampusExpressDelivery/SSL/xiaokuaisong.shop.pem
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGEjCCBPqgAwIBAgIQBbg2EGUqRzMeBv4XlQPfPzANBgkqhkiG9w0BAQsFADBu
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
|
||||||
|
RFYgVExTIENBIC0gRzIwHhcNMjUwMzEzMDAwMDAwWhcNMjUwNjEwMjM1OTU5WjAc
|
||||||
|
MRowGAYDVQQDExF4aWFva3VhaXNvbmcuc2hvcDCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||||
|
ggEPADCCAQoCggEBAO4AdSFAtVLcN4IWdw6NlSWgQvrwCVGqVTwpuFLgWQb484jJ
|
||||||
|
1H3qoXtTjwJMFAtQg7boefsWnJJ7IXmOgq3XzleapDKgr4OKKWr3Alro/XecKaTt
|
||||||
|
VKAY7G2DVLJWM8Kthd19PzdbBVDkDOelevXyGPinnaLOhR7GQ/xK1+8oQwWOB+En
|
||||||
|
tkOTUIy9dnllcrNyZ9OwE00wH1W7HsCQMXjIefI+dZFVNF4Yo3prom77YIgkijGu
|
||||||
|
CU1DNvrZXcQvV32+BLd8RU1nQCZ6feOaKlgM6A2vWLMzRmCa7N0xSSrAsbl3vMAQ
|
||||||
|
U+IkS2/oXMlZvFnpGsdOB5iYZdTWYU/qYO5h56ECAwEAAaOCAvwwggL4MB8GA1Ud
|
||||||
|
IwQYMBaAFHjfkZBf7t6s9sV169VMVVPvJEq2MB0GA1UdDgQWBBQXPuvYOoWcOMyK
|
||||||
|
b3LR/m5M+SEqOjAzBgNVHREELDAqghF4aWFva3VhaXNvbmcuc2hvcIIVd3d3Lnhp
|
||||||
|
YW9rdWFpc29uZy5zaG9wMD4GA1UdIAQ3MDUwMwYGZ4EMAQIBMCkwJwYIKwYBBQUH
|
||||||
|
AgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCBaAw
|
||||||
|
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGABggrBgEFBQcBAQR0MHIw
|
||||||
|
JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBKBggrBgEFBQcw
|
||||||
|
AoY+aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0VuY3J5cHRpb25FdmVyeXdo
|
||||||
|
ZXJlRFZUTFNDQS1HMi5jcnQwDAYDVR0TAQH/BAIwADCCAX8GCisGAQQB1nkCBAIE
|
||||||
|
ggFvBIIBawFpAHcATnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGV
|
||||||
|
jmc97gAABAMASDBGAiEAoYWQ8iavGTLIH4jqUngz50C0ZjZAnlTxgg8/YwjsQUoC
|
||||||
|
IQDgojkRl8fgVYI3jC0u/n8MNQEnoKTJI8Y9q3cAsm0+XgB3AHMgIg8IFor588Sm
|
||||||
|
iwqyappKAO71d4WKCE0FANSlQkRZAAABlY5nPhAAAAQDAEgwRgIhAPR2D8STMyua
|
||||||
|
aO386zeiuK50P3zUM7hXC6hkrRTq6HJaAiEAhNZWFG2XG93jldcd76I+o74Xl/3i
|
||||||
|
OS+6IgavCD15cYQAdQDm0jFjQHeMwRBBBtdxuc7B0kD2loSG+7qHMh39HjeOUAAA
|
||||||
|
AZWOZz4gAAAEAwBGMEQCIBDSrtuoMLTcOXWkLUd2wE1b/rOyJhrOpNzuyVSjiJl8
|
||||||
|
AiA+lA9UqElkIXJ7dVbv6+9Y3OviuCpFlhcL0HChF+C0gzANBgkqhkiG9w0BAQsF
|
||||||
|
AAOCAQEA0CZyVm1PtZh5EZoMu0vheFjgEeefq2qvqU5b0/aQaCXnLnBu694tBlL2
|
||||||
|
YZz+L0Q2wnzjBMczoJFBROEyauvHT4rtq/xkyUOtLl9XB4jD+H0pNWwJ1m69m9ED
|
||||||
|
7Tqam3PKTc4k7ICLRZtLTHk/3hW0EuAYpf8Ncm2Bqr8RHGVkQ4+5TyVuK3TzDrtG
|
||||||
|
ICX1+k8JQxupEWHzmZkcCf5qd1m+yv/qzkCQ2bqe48zFqMx+1Nw2mc82VBp+TXup
|
||||||
|
Gk9rNNStjj7+pDYNGBQDR35WXKgy1Nq8npqMLCZcFHLMld9hCfoRkjoYiINbCqBM
|
||||||
|
dpfu6Ss9Ap9isZv9IqW33n0WY/8HVw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEqjCCA5KgAwIBAgIQDeD/te5iy2EQn2CMnO1e0zANBgkqhkiG9w0BAQsFADBh
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
|
||||||
|
MjAeFw0xNzExMjcxMjQ2NDBaFw0yNzExMjcxMjQ2NDBaMG4xCzAJBgNVBAYTAlVT
|
||||||
|
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||||
|
b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH
|
||||||
|
MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO8Uf46i/nr7pkgTDqnE
|
||||||
|
eSIfCFqvPnUq3aF1tMJ5hh9MnO6Lmt5UdHfBGwC9Si+XjK12cjZgxObsL6Rg1njv
|
||||||
|
NhAMJ4JunN0JGGRJGSevbJsA3sc68nbPQzuKp5Jc8vpryp2mts38pSCXorPR+sch
|
||||||
|
QisKA7OSQ1MjcFN0d7tbrceWFNbzgL2csJVQeogOBGSe/KZEIZw6gXLKeFe7mupn
|
||||||
|
NYJROi2iC11+HuF79iAttMc32Cv6UOxixY/3ZV+LzpLnklFq98XORgwkIJL1HuvP
|
||||||
|
ha8yvb+W6JislZJL+HLFtidoxmI7Qm3ZyIV66W533DsGFimFJkz3y0GeHWuSVMbI
|
||||||
|
lfsCAwEAAaOCAU8wggFLMB0GA1UdDgQWBBR435GQX+7erPbFdevVTFVT7yRKtjAf
|
||||||
|
BgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8EBAMCAYYw
|
||||||
|
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C
|
||||||
|
AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
|
||||||
|
Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu
|
||||||
|
Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
|
||||||
|
/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
|
||||||
|
MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAoBs1eCLKakLtVRPFRjBIJ9LJ
|
||||||
|
L0s8ZWum8U8/1TMVkQMBn+CPb5xnCD0GSA6L/V0ZFrMNqBirrr5B241OesECvxIi
|
||||||
|
98bZ90h9+q/X5eMyOD35f8YTaEMpdnQCnawIwiHx06/0BfiTj+b/XQih+mqt3ZXe
|
||||||
|
xNCJqKexdiB2IWGSKcgahPacWkk/BAQFisKIFYEqHzV974S3FAz/8LIfD58xnsEN
|
||||||
|
GfzyIDkH3JrwYZ8caPTf6ZX9M1GrISN8HnWTtdNCH2xEajRa/h9ZBXjUyFKQrGk2
|
||||||
|
n2hcLrfZSbynEC/pSw/ET7H5nWwckjmAJ1l9fcnbqkU/pf6uMQmnfl0JQjJNSg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
10
CampusExpressDelivery/auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
// Generated by unplugin-auto-import
|
||||||
|
// biome-ignore lint: disable
|
||||||
|
export {}
|
||||||
|
declare global {
|
||||||
|
|
||||||
|
}
|
||||||
51
CampusExpressDelivery/components.d.ts
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
export {}
|
||||||
|
|
||||||
|
/* prettier-ignore */
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
AAvatar: typeof import('ant-design-vue/es')['Avatar']
|
||||||
|
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
|
||||||
|
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
|
||||||
|
AButton: typeof import('ant-design-vue/es')['Button']
|
||||||
|
ACard: typeof import('ant-design-vue/es')['Card']
|
||||||
|
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
|
||||||
|
ADescriptions: typeof import('ant-design-vue/es')['Descriptions']
|
||||||
|
ADescriptionsItem: typeof import('ant-design-vue/es')['DescriptionsItem']
|
||||||
|
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||||
|
ADrawer: typeof import('ant-design-vue/es')['Drawer']
|
||||||
|
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
||||||
|
AEmpty: typeof import('ant-design-vue/es')['Empty']
|
||||||
|
AForm: typeof import('ant-design-vue/es')['Form']
|
||||||
|
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||||
|
AImage: typeof import('ant-design-vue/es')['Image']
|
||||||
|
AInput: typeof import('ant-design-vue/es')['Input']
|
||||||
|
AInputSearch: typeof import('ant-design-vue/es')['InputSearch']
|
||||||
|
ALayout: typeof import('ant-design-vue/es')['Layout']
|
||||||
|
ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
|
||||||
|
ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
|
||||||
|
ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
|
||||||
|
AList: typeof import('ant-design-vue/es')['List']
|
||||||
|
AListItem: typeof import('ant-design-vue/es')['ListItem']
|
||||||
|
AListItemMeta: typeof import('ant-design-vue/es')['ListItemMeta']
|
||||||
|
AMenu: typeof import('ant-design-vue/es')['Menu']
|
||||||
|
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
||||||
|
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||||
|
APagination: typeof import('ant-design-vue/es')['Pagination']
|
||||||
|
ARangePicker: typeof import('ant-design-vue/es')['RangePicker']
|
||||||
|
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||||
|
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||||
|
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||||
|
ASpin: typeof import('ant-design-vue/es')['Spin']
|
||||||
|
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
|
||||||
|
ATable: typeof import('ant-design-vue/es')['Table']
|
||||||
|
ATag: typeof import('ant-design-vue/es')['Tag']
|
||||||
|
ATextarea: typeof import('ant-design-vue/es')['Textarea']
|
||||||
|
AUpload: typeof import('ant-design-vue/es')['Upload']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
CampusExpressDelivery/dist.zip
Normal file
13
CampusExpressDelivery/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>校快送</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
3952
CampusExpressDelivery/package-lock.json
generated
Normal file
30
CampusExpressDelivery/package.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "campusexpressdelivery",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vue-tsc -b && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ant-design-vue": "^4.2.6",
|
||||||
|
"axios": "^1.7.7",
|
||||||
|
"echarts": "^5.6.0",
|
||||||
|
"element-plus": "^2.8.8",
|
||||||
|
"pinia": "^2.2.6",
|
||||||
|
"pinia-plugin-persistedstate": "^4.1.3",
|
||||||
|
"vue": "^3.5.12",
|
||||||
|
"vue-router": "^4.4.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
|
"sass-embedded": "^1.81.0",
|
||||||
|
"typescript": "~5.6.2",
|
||||||
|
"unplugin-auto-import": "^0.18.5",
|
||||||
|
"unplugin-vue-components": "^0.27.4",
|
||||||
|
"vite": "^5.4.10",
|
||||||
|
"vue-tsc": "^2.1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
CampusExpressDelivery/public/vite.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
13
CampusExpressDelivery/src/App.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
<a-config-provider :locale="zhCN">
|
||||||
|
<router-view/>
|
||||||
|
</a-config-provider>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import zhCN from "ant-design-vue/es/locale/zh_CN";
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import 'dayjs/locale/zh-cn';
|
||||||
|
|
||||||
|
dayjs.locale('zh-cn');
|
||||||
|
</script>
|
||||||
31
CampusExpressDelivery/src/api/myAxios.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// 创建实例时配置默认值
|
||||||
|
import axios from "axios";
|
||||||
|
import router from "../router";
|
||||||
|
|
||||||
|
//const viteEnv = import.meta.env;
|
||||||
|
|
||||||
|
const myAxios = axios.create({
|
||||||
|
withCredentials: true,
|
||||||
|
//baseURL:'http://39.101.78.35:6271/api'
|
||||||
|
// baseURL:'http://localhost:9999'
|
||||||
|
// baseURL:'http://39.101.78.35:6445/api'
|
||||||
|
// baseURL:'https://xiaokuaisong.shop:6448/api'
|
||||||
|
baseURL:'https://xiaokuaisong.shop/api'
|
||||||
|
});
|
||||||
|
|
||||||
|
myAxios.interceptors.request.use(function (config) {
|
||||||
|
return config;
|
||||||
|
}, function (error) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
myAxios.interceptors.response.use(function (response: any) {
|
||||||
|
if (response.data.code === 40100) {
|
||||||
|
router.replace('/')
|
||||||
|
}
|
||||||
|
return response.data;
|
||||||
|
}, function (error) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default myAxios;
|
||||||
BIN
CampusExpressDelivery/src/assets/background.png
Normal file
|
After Width: | Height: | Size: 4.8 MiB |
BIN
CampusExpressDelivery/src/assets/login/bgi.jpg
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
CampusExpressDelivery/src/assets/login/hidePassword.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
CampusExpressDelivery/src/assets/login/image.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
CampusExpressDelivery/src/assets/login/showPassword.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
CampusExpressDelivery/src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
48
CampusExpressDelivery/src/layout/ManageLayout.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<div id="manage">
|
||||||
|
<a-layout has-sider>
|
||||||
|
<a-layout-sider :style="{ width: '200px' }">
|
||||||
|
<ManageSidebar/>
|
||||||
|
</a-layout-sider>
|
||||||
|
<a-layout>
|
||||||
|
<a-layout-header :style="{ background: '#fff', padding: 0}">
|
||||||
|
<ManageHeader/>
|
||||||
|
</a-layout-header>
|
||||||
|
<a-layout-content class="main">
|
||||||
|
<router-view :key="key" class="main-card"/>
|
||||||
|
</a-layout-content>
|
||||||
|
</a-layout>
|
||||||
|
</a-layout>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ManageHeader from "./manage/ManageHeader.vue";
|
||||||
|
import ManageSidebar from "./manage/ManageSidebar.vue";
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const key = () => {
|
||||||
|
return route.path + Math.random();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
#manage {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
padding: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
flex: 1;
|
||||||
|
flex-basis: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
171
CampusExpressDelivery/src/layout/manage/ManageHeader.vue
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<template>
|
||||||
|
<div class="manage-header">
|
||||||
|
<div class="header-left">
|
||||||
|
<a-breadcrumb class="breadcrumb">
|
||||||
|
<a-breadcrumb-item>校快送后台管理系统</a-breadcrumb-item>
|
||||||
|
<a-breadcrumb-item class="routeName">{{ route.name }}</a-breadcrumb-item>
|
||||||
|
</a-breadcrumb>
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<!-- <div class="bell">-->
|
||||||
|
<!-- <BellTwoTone/>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<div class="name">
|
||||||
|
{{ store.loginUser.userRole === "notLogin" ? '未登录' : store.loginUser.userRole }}
|
||||||
|
</div>
|
||||||
|
<div class="user">
|
||||||
|
<a-dropdown>
|
||||||
|
<a-avatar :size="40" class="user-avatar" :src="store.loginUser.avatarUrl"/>
|
||||||
|
<template #overlay>
|
||||||
|
<a-menu>
|
||||||
|
<a-menu-item @click="logout">
|
||||||
|
<LogoutOutlined />
|
||||||
|
退出登录
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item @click="showDrawer">
|
||||||
|
<UserOutlined />
|
||||||
|
个人中心
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-drawer
|
||||||
|
title="个人中心"
|
||||||
|
:placement="placement"
|
||||||
|
:closable="false"
|
||||||
|
:open="open"
|
||||||
|
@close="onClose"
|
||||||
|
class="custom-class"
|
||||||
|
>
|
||||||
|
<a-avatar :size="64" :src="store.loginUser.avatarUrl"></a-avatar>
|
||||||
|
|
||||||
|
<div class="message">
|
||||||
|
<p class="firstmessage">用户名:{{ store.loginUser.username }}</p>
|
||||||
|
<p>账号ID:{{ store.loginUser.username }}</p>
|
||||||
|
<p>注册时间:2024-06-20</p>
|
||||||
|
<p>账号权限:{{store.loginUser.userRole}}</p>
|
||||||
|
<p>联系方式:{{store.loginUser.phone}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</a-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {useRoute, useRouter} from "vue-router";
|
||||||
|
import {userStore} from "../../store/userStore.ts";
|
||||||
|
import {UserOutlined,LogoutOutlined} from '@ant-design/icons-vue';
|
||||||
|
import myAxios from "../../api/myAxios.ts";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import type { DrawerProps } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
const store = userStore()
|
||||||
|
|
||||||
|
|
||||||
|
const placement = ref<DrawerProps['placement']>('right');
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
|
||||||
|
const showDrawer = () => {
|
||||||
|
open.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
open.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登出
|
||||||
|
*/
|
||||||
|
const logout = async () => {
|
||||||
|
const res: any = await myAxios.post("/user/logout", {})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
// 清除用户角色
|
||||||
|
store.$reset()
|
||||||
|
await router.replace('/')
|
||||||
|
message.success('登出成功');
|
||||||
|
} else {
|
||||||
|
message.error(`登出失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.manage-header {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 2px solid #ccced7;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-left {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-left .breadcrumb {
|
||||||
|
color: black;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.routeName {
|
||||||
|
font-size: 13px;
|
||||||
|
padding-top: 10px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
}
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right .bell {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right .name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right .user {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
cursor: pointer;
|
||||||
|
//transition: all 0.5s;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar:hover {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-class img{
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
float: right;
|
||||||
|
margin-right: 100px;
|
||||||
|
}
|
||||||
|
.firstmessage {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
91
CampusExpressDelivery/src/layout/manage/ManageSidebar.vue
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<a-menu
|
||||||
|
v-model:selectedKeys="selectedKeys"
|
||||||
|
mode="inline"
|
||||||
|
theme="dark"
|
||||||
|
style="max-height: 200vh; min-height: 100vh"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<a-menu-item key="/index">
|
||||||
|
<PieChartOutlined />
|
||||||
|
<span>首页</span>
|
||||||
|
</a-menu-item>
|
||||||
|
<a-sub-menu>
|
||||||
|
<template #title>
|
||||||
|
<span>
|
||||||
|
<UserOutlined />
|
||||||
|
<span>用户管理</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<a-menu-item key="/userList">用户列表</a-menu-item>
|
||||||
|
</a-sub-menu>
|
||||||
|
<a-sub-menu>
|
||||||
|
<template #title>
|
||||||
|
<span>
|
||||||
|
<UserOutlined />
|
||||||
|
<span>快送员管理</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<a-menu-item key="/errandList">快送员列表</a-menu-item>
|
||||||
|
<a-menu-item key="/runList">订单列表</a-menu-item>
|
||||||
|
</a-sub-menu>
|
||||||
|
<a-sub-menu>
|
||||||
|
<template #title>
|
||||||
|
<span>
|
||||||
|
<ShopOutlined />
|
||||||
|
<span>店铺管理</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<a-menu-item key="/businessManage">门店管理</a-menu-item>
|
||||||
|
<a-menu-item key="/storeList">订单列表</a-menu-item>
|
||||||
|
<a-menu-item key="/log">店铺操作日志</a-menu-item>
|
||||||
|
</a-sub-menu>
|
||||||
|
<a-sub-menu>
|
||||||
|
<template #title>
|
||||||
|
<span>
|
||||||
|
<SettingOutlined />
|
||||||
|
<span>系统管理</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<a-menu-item key="/info">管理员公告管理</a-menu-item>
|
||||||
|
<!-- <a-menu-item key="/businessInfoManage">商家公告管理</a-menu-item>-->
|
||||||
|
<a-menu-item key="/category">分类管理</a-menu-item>
|
||||||
|
<a-menu-item key="/carousel">轮播图管理</a-menu-item>
|
||||||
|
</a-sub-menu>
|
||||||
|
<a-menu-item key="/CustomerService">
|
||||||
|
<AlipayOutlined />
|
||||||
|
<span>人工客服</span>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {UserOutlined, ShopOutlined, SettingOutlined,AlipayOutlined,PieChartOutlined} from '@ant-design/icons-vue';
|
||||||
|
import {useRoute, useRouter} from "vue-router";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
// 选中侧边栏
|
||||||
|
const selectedKeys = ref<string[]>(['/userList']);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setSelectedKey()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 根据路由设置当前选中侧边栏
|
||||||
|
const setSelectedKey = () => {
|
||||||
|
selectedKeys.value = [route.path];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路由跳转
|
||||||
|
const handleClick = (item: any) => {
|
||||||
|
router.push(item.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
14
CampusExpressDelivery/src/main.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import {createApp} from 'vue'
|
||||||
|
import './style.css'
|
||||||
|
import App from './App.vue'
|
||||||
|
import pinia from "./store";
|
||||||
|
import router from "./router";
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
// 配置路由
|
||||||
|
app.use(router)
|
||||||
|
// 配置pinia
|
||||||
|
app.use(pinia)
|
||||||
|
// 挂在实例
|
||||||
|
app.mount('#app')
|
||||||
|
|
||||||
11
CampusExpressDelivery/src/router/index.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import {createRouter, createWebHashHistory} from "vue-router";
|
||||||
|
import {routes} from "./routes";
|
||||||
|
|
||||||
|
// 创建路由实例并传递 `routes` 配置
|
||||||
|
const router = createRouter({
|
||||||
|
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes, // `routes: routes` 的缩写
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
121
CampusExpressDelivery/src/router/routes.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// 将路由规则 routes 导出
|
||||||
|
export const routes = [
|
||||||
|
// 全局路由(无需嵌套上左右整体布局)
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'Login',
|
||||||
|
component: () => import("../view/Login.vue")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/test',
|
||||||
|
name: '全局测试页面',
|
||||||
|
component: () => import("../view/Test.vue"),
|
||||||
|
},
|
||||||
|
// 管理端
|
||||||
|
{
|
||||||
|
path: '/manage',
|
||||||
|
component: () => import("../layout/ManageLayout.vue"),
|
||||||
|
children: [
|
||||||
|
// 首页
|
||||||
|
{
|
||||||
|
path: '/index',
|
||||||
|
name: '首页',
|
||||||
|
component: () => import("../view/Index.vue"),
|
||||||
|
},
|
||||||
|
// 账户管理
|
||||||
|
{
|
||||||
|
path: '/userList',
|
||||||
|
name: '用户列表',
|
||||||
|
component: () => import("../view/user/UserList.vue"),
|
||||||
|
},
|
||||||
|
//快送员管理
|
||||||
|
{
|
||||||
|
path: '/errandList',
|
||||||
|
name: '快送员列表',
|
||||||
|
component: () => import("../view/errand/errandList.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/errandInfo',
|
||||||
|
name: '快送员审核',
|
||||||
|
component: () => import("../view/errand/errandInfo.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/runList',
|
||||||
|
name: '快送员订单',
|
||||||
|
component: () => import("../view/errand/runList.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/errandOrderList',
|
||||||
|
name: '快送员订单列表',
|
||||||
|
component: () => import("../view/errand/errandOrderList.vue"),
|
||||||
|
},
|
||||||
|
// 店铺管理
|
||||||
|
{
|
||||||
|
path: '/businessManage',
|
||||||
|
name: '门店管理',
|
||||||
|
component: () => import("../view/shop/business/BusinessManage.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/businessInfo',
|
||||||
|
name: '门店详情',
|
||||||
|
component: () => import("../view/shop/business/BusinessInfo.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/DishGroup',
|
||||||
|
name: '菜品分组详情',
|
||||||
|
component: () => import("../view/shop/business/DishGroup.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/Dish',
|
||||||
|
name: '菜品详情',
|
||||||
|
component: () => import("../view/shop/business/Dish.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/storeList',
|
||||||
|
name: '店铺列表',
|
||||||
|
component: () => import("../view/shop/order/StoreList.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/orderList',
|
||||||
|
name: '订单列表',
|
||||||
|
component: () => import("../view/shop/order/OrderList.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/orderDetail',
|
||||||
|
name: '订单详情',
|
||||||
|
component: () => import("../view/shop/order/OrderDetail.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/log',
|
||||||
|
name: '门店操作日志',
|
||||||
|
component: () => import("../view/shop/BusinessLog.vue"),
|
||||||
|
},
|
||||||
|
// 系统管理
|
||||||
|
{
|
||||||
|
path: '/info',
|
||||||
|
name: '公告管理',
|
||||||
|
component: () => import("../view/system/Info.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/businessInfoManage',
|
||||||
|
name: '商家公告管理',
|
||||||
|
component: () => import("../view/system/BusinessInfo.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/category',
|
||||||
|
name: '分类管理',
|
||||||
|
component: () => import("../view/system/Category.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/carousel',
|
||||||
|
name: '轮播图管理',
|
||||||
|
component: () => import("../view/system/Carousel/Carousel.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/CustomerService',
|
||||||
|
name: '人工客服',
|
||||||
|
component: () => import("../view/Service/CustomerService.vue"),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
10
CampusExpressDelivery/src/store/index.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import {createPinia} from 'pinia'
|
||||||
|
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||||
|
|
||||||
|
const pinia = createPinia();
|
||||||
|
pinia.use(piniaPluginPersistedstate)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default pinia
|
||||||
32
CampusExpressDelivery/src/store/userStore.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import {defineStore} from 'pinia'
|
||||||
|
import myAxios from "../api/myAxios";
|
||||||
|
|
||||||
|
export const userStore = defineStore('user', {
|
||||||
|
// 推荐使用 完整类型推断的箭头函数
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
loginUser: {
|
||||||
|
username: '未登录',
|
||||||
|
avatarUrl: '',
|
||||||
|
userRole: 'notLogin',
|
||||||
|
phone:''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, persist: true,
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
// 获取登录用户信息
|
||||||
|
async getLoginUser() {
|
||||||
|
// 请求登录信息
|
||||||
|
const res: any = await myAxios.get('/user/current');
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
console.log("56765765756567")
|
||||||
|
this.updateUser(res.data)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 更新用户信息
|
||||||
|
updateUser(payLoad: any) {
|
||||||
|
this.loginUser = payLoad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
48
CampusExpressDelivery/src/style.css
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
html {
|
||||||
|
/* 滚动时采用平滑过渡 */
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 管理页面全局样式 */
|
||||||
|
|
||||||
|
.main-card {
|
||||||
|
min-height: calc(100vh - 100px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
display: flex;
|
||||||
|
background-color: white;
|
||||||
|
height: auto;
|
||||||
|
box-shadow: 0 0 1px 1px #dedede;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.middle-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-box {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 0 1px 1px #dedede;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
margin: 20px 0 20px 0;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.txt {
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 500px;
|
||||||
|
}
|
||||||
11
CampusExpressDelivery/src/utils/TableConfig.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// 时间处理
|
||||||
|
import router from "../router";
|
||||||
|
|
||||||
|
export const formatTime = (row: any) => {
|
||||||
|
let data = row.value;
|
||||||
|
return data.slice(0, 16).replace('T', '~');
|
||||||
|
}
|
||||||
|
|
||||||
|
export const backPage = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
338
CampusExpressDelivery/src/view/Index.vue
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
import BrokenLine from "./echarts/BrokenLine.vue";
|
||||||
|
import myAxios from "../api/myAxios.ts";
|
||||||
|
import { ElDatePicker,ElAlert} from 'element-plus'
|
||||||
|
import 'element-plus/dist/index.css'
|
||||||
|
const isLoading = ref(true)
|
||||||
|
|
||||||
|
const dailyTransactions = ref('')
|
||||||
|
const fiscalRevenue = ref('')
|
||||||
|
const value1:any = ref<[Date, Date] | null>(null)
|
||||||
|
const defaultTime1 = new Date(2000, 1, 1, 12, 0, 0)
|
||||||
|
|
||||||
|
// 日期格式化函数
|
||||||
|
const formatDate:any = (date: Date | null | undefined): string => {
|
||||||
|
if (!date) return ""
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(date.getDate()).padStart(2, '0')
|
||||||
|
return `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听日期选择变化
|
||||||
|
watch(value1, (newVal) => {
|
||||||
|
let startTime = ""
|
||||||
|
let endTime = ""
|
||||||
|
if (newVal && newVal.length === 2) {
|
||||||
|
startTime = formatDate(newVal[0])
|
||||||
|
endTime = formatDate(newVal[1])
|
||||||
|
}
|
||||||
|
fetchRevenue(startTime, endTime)
|
||||||
|
totalNumber(startTime, endTime)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取财政收入数据
|
||||||
|
const fetchRevenue:any = async (startTime: string = "", endTime: string = "") => {
|
||||||
|
try {
|
||||||
|
const response:any = await myAxios.post('/orders/count', {
|
||||||
|
businessId: "",
|
||||||
|
businessName: "",
|
||||||
|
businessState: 0,
|
||||||
|
categoryId: 0,
|
||||||
|
endTime: endTime,
|
||||||
|
startTime: startTime,
|
||||||
|
state: 0,
|
||||||
|
type: "money"
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (response.code === 0) {
|
||||||
|
fiscalRevenue.value = parseFloat(response.data).toFixed(2)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching revenue:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取交易单量数据
|
||||||
|
const totalNumber:any = async (startTime: string = "", endTime: string = "") => {
|
||||||
|
try {
|
||||||
|
const response:any = await myAxios.post('/orders/count', {
|
||||||
|
businessId: "",
|
||||||
|
businessName: "",
|
||||||
|
businessState: 0,
|
||||||
|
categoryId: 0,
|
||||||
|
endTime: endTime,
|
||||||
|
startTime: startTime,
|
||||||
|
state: 0,
|
||||||
|
type: "number"
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (response.code === 0) {
|
||||||
|
dailyTransactions.value = response.data
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching total number:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const refundList = ref<string[]>([]) // 明确类型为字符串数组
|
||||||
|
|
||||||
|
const getReasonRefund = async () => {
|
||||||
|
try {
|
||||||
|
const response:any = await myAxios.post('/refund/list/reson', {}, { // 添加空请求体
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.code === 0) {
|
||||||
|
console.log(response)
|
||||||
|
// 确保数据是数组格式(根据你的接口返回结构调整)
|
||||||
|
refundList.value = Array.isArray(response.data) ? response.data : []
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('请求失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
await Promise.all([
|
||||||
|
fetchRevenue(),
|
||||||
|
totalNumber(),
|
||||||
|
getReasonRefund()
|
||||||
|
])
|
||||||
|
} catch (error) {
|
||||||
|
console.error('数据加载失败:', error)
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<a-spin v-if="isLoading" class="loading-spinner" />
|
||||||
|
<div v-if="!isLoading">
|
||||||
|
<div class="container">
|
||||||
|
<div class="box">
|
||||||
|
<div class="number">每日交易量</div>
|
||||||
|
<div class="number">{{ dailyTransactions }}</div>
|
||||||
|
<div class="number">食堂总共交易量为{{ dailyTransactions }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<div class="number">财政收入</div>
|
||||||
|
<div class="number">¥{{ fiscalRevenue }}</div>
|
||||||
|
<div class="number">每日财政收入金额为¥{{ fiscalRevenue }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="boxTime">
|
||||||
|
<div class="boxTime-number">时间选择器</div>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="value1"
|
||||||
|
type="datetimerange"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="defaultTime1"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert-chart-container">
|
||||||
|
<div class="alert-container">
|
||||||
|
<div class="boxTime-number">退款原因申请</div>
|
||||||
|
<template v-if="refundList.length === 0">
|
||||||
|
<a-empty />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="refund-list">
|
||||||
|
<el-alert
|
||||||
|
v-for="(item, index) in refundList"
|
||||||
|
:key="index"
|
||||||
|
:title="`退款原因 ${index + 1}`"
|
||||||
|
type="error"
|
||||||
|
:description="item"
|
||||||
|
show-icon
|
||||||
|
:closable="false"
|
||||||
|
class="alert-item"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<BrokenLine />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.container {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
float: left;
|
||||||
|
width: 30%;
|
||||||
|
margin: 1%;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
}
|
||||||
|
.boxTime {
|
||||||
|
float: left;
|
||||||
|
margin: 1%;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
.boxTime-number {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 20px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.number:first-child {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number:nth-child(2) {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #4CAF50; /* Green color for the revenue amount */
|
||||||
|
}
|
||||||
|
|
||||||
|
.number:nth-child(3) {
|
||||||
|
color: #4CAF50; /* Green color for the change since last week */
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.brokenLine {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 60%;
|
||||||
|
height: 40%;
|
||||||
|
}
|
||||||
|
.ordermethod {
|
||||||
|
width: 100%;
|
||||||
|
height: 40%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: start;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-alert {
|
||||||
|
margin: 20px 0 0;
|
||||||
|
}
|
||||||
|
.el-alert:first-child {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.alertMessage {
|
||||||
|
width: 50%;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 15px;
|
||||||
|
margin: 1%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 新增布局样式 */
|
||||||
|
.alert-chart-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin: 1%;
|
||||||
|
height: 500px;
|
||||||
|
width: calc(100% - 2%); /* 补偿左右margin */
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-container {
|
||||||
|
flex: 0 0 30%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.16);
|
||||||
|
height: 500px;
|
||||||
|
|
||||||
|
.refund-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 8px;
|
||||||
|
|
||||||
|
.alert-item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 自定义滚动条样式 */
|
||||||
|
.refund-list::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-list::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-list::-webkit-scrollbar-thumb {
|
||||||
|
background: #888;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-list::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
flex: 1;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.16);
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式调整 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.alert-chart-container {
|
||||||
|
flex-direction: column;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-container {
|
||||||
|
flex: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
293
CampusExpressDelivery/src/view/Login.vue
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
<template>
|
||||||
|
<div id="login">
|
||||||
|
<form>
|
||||||
|
<div class="box" @submit.prevent>
|
||||||
|
<h2>校快送后台管理系统</h2>
|
||||||
|
<div class="input-box">
|
||||||
|
<label>账号</label>
|
||||||
|
<input type="text" placeholder="账号" v-model="userAccount"/>
|
||||||
|
</div>
|
||||||
|
<div class="input-box">
|
||||||
|
<label>密码</label>
|
||||||
|
<div class="password-container">
|
||||||
|
<input
|
||||||
|
class="password"
|
||||||
|
:type="showPassword ? 'text' : 'password'"
|
||||||
|
placeholder="密码"
|
||||||
|
v-model="userPassword"
|
||||||
|
autocomplete="new-password"
|
||||||
|
/>
|
||||||
|
<div @click="togglePassword" class="password-toggle">
|
||||||
|
<img
|
||||||
|
src="../assets/login/hidePassword.png"
|
||||||
|
v-show="!showPassword"
|
||||||
|
alt="隐藏密码"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="../assets/login/showPassword.png"
|
||||||
|
v-show="showPassword"
|
||||||
|
alt="显示密码"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="btn-box">
|
||||||
|
<div>
|
||||||
|
<button @click="onLogin" @keyup.enter="onLogin" type="button">登录</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
|
import {ref} from 'vue'
|
||||||
|
import {userStore} from "../store/userStore.ts";
|
||||||
|
import myAxios from "../api/myAxios";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
|
||||||
|
const store = userStore()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
//默认闭眼图标
|
||||||
|
let showPassword = ref(false)
|
||||||
|
const userAccount = ref('');
|
||||||
|
const userPassword = ref('');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
*/
|
||||||
|
const onLogin = async () => {
|
||||||
|
try {
|
||||||
|
const res: any = await myAxios.post("/user/login", {
|
||||||
|
appName: 'admin',
|
||||||
|
userAccount: userAccount.value,
|
||||||
|
userPassword: userPassword.value
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.code === 0 && res?.data) {
|
||||||
|
console.log(res);
|
||||||
|
// 存储用户角色
|
||||||
|
await store.getLoginUser();
|
||||||
|
// 添加调试信息
|
||||||
|
console.log('Redirecting to /index');
|
||||||
|
//await router.replace('/index');
|
||||||
|
router.push('/index');
|
||||||
|
message.success('登录成功');
|
||||||
|
} else {
|
||||||
|
message.error(`登录失败:${res.description}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Login error:', error);
|
||||||
|
message.error('登录失败,请稍后再试');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换密码显示/隐藏
|
||||||
|
*/
|
||||||
|
const togglePassword = () => {
|
||||||
|
showPassword.value = !showPassword.value
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
background-image: url('../assets/background.png');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
border-left: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-right: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background: rgba(50, 50, 50, 0.2);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box > h2 {
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .input-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .input-box label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .input-box input {
|
||||||
|
letter-spacing: 1px;
|
||||||
|
font-size: 14px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 250px;
|
||||||
|
height: 35px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
outline: none;
|
||||||
|
padding: 0 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 密码输入框容器 */
|
||||||
|
.password-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-container .password {
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 40px; /* 为图标留出空间 */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 禁用浏览器默认的密码显示功能 */
|
||||||
|
.password::-ms-reveal,
|
||||||
|
.password::-ms-clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-toggle {
|
||||||
|
position: absolute;
|
||||||
|
right: 6px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-toggle img {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .input-box input:focus {
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .btn-box {
|
||||||
|
width: 250px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .btn-box > a {
|
||||||
|
outline: none;
|
||||||
|
display: block;
|
||||||
|
width: 250px;
|
||||||
|
text-align: end;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .btn-box > a:hover {
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .btn-box > div {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .btn-box > div > button {
|
||||||
|
outline: none;
|
||||||
|
margin-top: 10px;
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .btn-box > div > button:nth-of-type(1) {
|
||||||
|
width: 250px;
|
||||||
|
height: 35px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
border: 1px solid rgba(64, 149, 229, 0.7);
|
||||||
|
background: rgba(64, 149, 229, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .btn-box > div > button:nth-of-type(2) {
|
||||||
|
width: 120px;
|
||||||
|
height: 35px;
|
||||||
|
margin-left: 10px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
border: 1px solid rgba(64, 149, 229, 0.7);
|
||||||
|
background: rgba(64, 149, 229, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box .btn-box > div > button:hover {
|
||||||
|
border: 1px solid rgba(64, 149, 229, 0.7);
|
||||||
|
background: rgba(64, 149, 229, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1440px) {
|
||||||
|
.container {
|
||||||
|
width: 28%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1366px) {
|
||||||
|
.container {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1280px) {
|
||||||
|
.container {
|
||||||
|
width: 33%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agileheader h1 {
|
||||||
|
font-size: 41px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container h2 {
|
||||||
|
font-size: 27px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1080px) {
|
||||||
|
.container {
|
||||||
|
width: 49%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
CampusExpressDelivery/src/view/Service/CustomerService.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div style="width: 100%; height: 100%;">
|
||||||
|
<iframe
|
||||||
|
:src="chatUrl"
|
||||||
|
frameborder="0"
|
||||||
|
style="width: 100%; height: 100%; border: none;"
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const chatUrl = "https://ccs.cloud.alipay.com/bench/online";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 样式部分保持不变 */
|
||||||
|
</style>
|
||||||
3
CampusExpressDelivery/src/view/Test.vue
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<div>123</div>
|
||||||
|
</template>
|
||||||
202
CampusExpressDelivery/src/view/echarts/BrokenLine.vue
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import * as echarts from "echarts";
|
||||||
|
import myAxios from "../../api/myAxios.ts";
|
||||||
|
|
||||||
|
const main = ref();
|
||||||
|
const orderData = ref<any[]>([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
getNumberOrder();
|
||||||
|
});
|
||||||
|
|
||||||
|
const getNumberOrder = async () => {
|
||||||
|
try {
|
||||||
|
const response:any = await myAxios.post(
|
||||||
|
"/orders/list/numnber",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (response.code === 0 && Array.isArray(response.data)) {
|
||||||
|
orderData.value = response.data.reverse(); // 反转数组顺序以匹配日期排列
|
||||||
|
updateChart();
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const myChart = echarts.init(main.value);
|
||||||
|
// 初始空配置
|
||||||
|
myChart.setOption(getChartOption());
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateChart = () => {
|
||||||
|
const myChart = echarts.getInstanceByDom(main.value);
|
||||||
|
if (myChart) {
|
||||||
|
myChart.setOption(getChartOption());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getChartOption = () => {
|
||||||
|
// 提取数据并处理为图表需要的格式
|
||||||
|
const dates = orderData.value.map((item) => item.date);
|
||||||
|
const takeOutData = orderData.value.map((item) => parseInt(item.takeOutNum));
|
||||||
|
const eatInData = orderData.value.map((item) => parseInt(item.eatInNum));
|
||||||
|
const selfLiftData = orderData.value.map((item) => parseInt(item.selfLiftNum));
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: ["#80FFA5", "#00DDFF", "#37A2FF", "#FF0087", "#FFBF00"],
|
||||||
|
title: {
|
||||||
|
text: "订单数据趋势图",
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: "axis",
|
||||||
|
axisPointer: {
|
||||||
|
type: "cross",
|
||||||
|
label: {
|
||||||
|
backgroundColor: "#6a7985",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ["外卖订单", "堂食订单", "自提订单"], // 修正中文名称
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
feature: {
|
||||||
|
saveAsImage: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: "3%",
|
||||||
|
right: "4%",
|
||||||
|
bottom: "3%",
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
boundaryGap: false,
|
||||||
|
data: dates, // 动态日期数据
|
||||||
|
},
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: "value",
|
||||||
|
name: "订单数量",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "外卖订单",
|
||||||
|
type: "line",
|
||||||
|
stack: "Total",
|
||||||
|
smooth: true,
|
||||||
|
lineStyle: {
|
||||||
|
width: 0,
|
||||||
|
},
|
||||||
|
showSymbol: false,
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.8,
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: "rgb(128, 255, 165)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: "rgb(1, 191, 236)",
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: "series",
|
||||||
|
},
|
||||||
|
data: takeOutData, // 动态数据
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "堂食订单",
|
||||||
|
type: "line",
|
||||||
|
stack: "Total",
|
||||||
|
smooth: true,
|
||||||
|
lineStyle: {
|
||||||
|
width: 0,
|
||||||
|
},
|
||||||
|
showSymbol: false,
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.8,
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: "rgb(0, 221, 255)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: "rgb(77, 119, 255)",
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: "series",
|
||||||
|
},
|
||||||
|
data: eatInData, // 动态数据
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "自提订单",
|
||||||
|
type: "line",
|
||||||
|
stack: "Total",
|
||||||
|
smooth: true,
|
||||||
|
lineStyle: {
|
||||||
|
width: 0,
|
||||||
|
},
|
||||||
|
showSymbol: false,
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.8,
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: "rgb(255, 0, 135)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: "rgb(135, 0, 157)",
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: "series",
|
||||||
|
},
|
||||||
|
data: selfLiftData, // 动态数据
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="echarts">
|
||||||
|
<div style="width: 100%; height: 100%; margin-top: 1rem">
|
||||||
|
<div ref="main" style="width: 100%; height: 100%"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.echarts {
|
||||||
|
width: 90%;
|
||||||
|
height: 80%;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #ffffff;
|
||||||
|
min-width: 0;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
80
CampusExpressDelivery/src/view/echarts/ordermethod.vue
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import * as echarts from "echarts";
|
||||||
|
|
||||||
|
|
||||||
|
const main = ref();
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const myChart = echarts.init(main.value);
|
||||||
|
let option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
top: '5%',
|
||||||
|
left: 'center'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Access From',
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['40%', '70%'],
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
padAngle: 5,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: 10
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'center'
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
fontSize: 40,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{ value: 735, name: '跑腿类' },
|
||||||
|
{ value: 580, name: '自提类' },
|
||||||
|
{ value: 484, name: '外卖类' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
myChart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="echarts">
|
||||||
|
<div style="width: 100%; height: 100%; margin-top: 1rem">
|
||||||
|
|
||||||
|
<div ref="main" style="width: 100%; height: 100%"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.echarts {
|
||||||
|
width: 50%;
|
||||||
|
height: 80%;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #ffffff;
|
||||||
|
min-width: 0;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
180
CampusExpressDelivery/src/view/errand/errandInfo.vue
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<template>
|
||||||
|
<a-card :loading="loading">
|
||||||
|
<div >
|
||||||
|
<a-descriptions size="default" bordered class="txt">
|
||||||
|
<a-descriptions-item label="头像">
|
||||||
|
<template v-slot>
|
||||||
|
<a-avatar :src="errandInfo.errandAvatarUrl" style="width: 100px;height: 100px;"/>
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="用户名称">{{ errandInfo?.errandName }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="用户性别">
|
||||||
|
<div v-if="errandInfo.gender === 1">
|
||||||
|
<a-tag color="blue">男</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="errandInfo.gender === 0">
|
||||||
|
<a-tag color="pink">女</a-tag>
|
||||||
|
</div>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="联系方式">{{ errandInfo?.errandPhone }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="配送范围">{{ errandInfo?.distributionScope }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="银行卡号">{{ errandInfo?.bankCard }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="身份证正面">
|
||||||
|
<template v-slot>
|
||||||
|
<a-image :src="errandInfo.frontIdCard" style="width: 158.5px; height: 100px;"/>
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="身份证反面">
|
||||||
|
<template v-slot>
|
||||||
|
<a-image :src="errandInfo.backIdCard" style="width: 158.5px; height: 100px"/>
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="当前状态">
|
||||||
|
<div v-if="errandInfo.state === 0">
|
||||||
|
<a-tag color="orange">未审核</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="errandInfo.state === 1">
|
||||||
|
<a-tag color="green">快送员正常</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="errandInfo.state === 2">
|
||||||
|
<a-tag color="red">快送员驳回</a-tag>
|
||||||
|
</div>
|
||||||
|
</a-descriptions-item>
|
||||||
|
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'businessAvatar'">
|
||||||
|
<a-avatar :src="record.businessAvatar"/>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'license'">
|
||||||
|
<a-image :src="record.license" style="width: 100px;height: 100px;"></a-image>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'frontIdCard'">
|
||||||
|
<a-image :src="record.frontIdCard" style="width: 100px;height: 100px;"></a-image>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'backIdCard'">
|
||||||
|
<a-image :src="record.backIdCard" style="width: 100px;height: 100px;"></a-image>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'state'">
|
||||||
|
<div v-if="record.state === 0">
|
||||||
|
<a-tag color="orange">未审核</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 1">
|
||||||
|
<a-tag color="green">已通过</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 2">
|
||||||
|
<a-tag color="red">未通过</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-descriptions>
|
||||||
|
</div>
|
||||||
|
<a-space>
|
||||||
|
<div class="button-box">
|
||||||
|
<a-button
|
||||||
|
class="button-s"
|
||||||
|
size="small"
|
||||||
|
type="default"
|
||||||
|
style="color: blue"
|
||||||
|
@click="backPage">返回
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
class="button-s"
|
||||||
|
size="small" v-if="state === 0"
|
||||||
|
type="primary"
|
||||||
|
style="color: white; margin-left: 15px"
|
||||||
|
danger
|
||||||
|
@click="update(2)">未通过
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
class="button-s"
|
||||||
|
size="small" v-if="state === 0"
|
||||||
|
type="primary"
|
||||||
|
style="color: white; margin-left: 15px"
|
||||||
|
@click="update(1)">通过
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</a-space>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import myAxios from "../../api/myAxios";
|
||||||
|
import {backPage} from "../../utils/TableConfig";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import router from "../../router";
|
||||||
|
|
||||||
|
const state = ref(0)
|
||||||
|
const route = useRoute();
|
||||||
|
const loading = ref(false);
|
||||||
|
const errandInfo: any = ref({});
|
||||||
|
const errandId = ref<string | null>(null);
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof route.query.id === 'string') {
|
||||||
|
errandId.value = route.query.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(errandId.value);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if(errandId.value !== null) {
|
||||||
|
getErrandVO(errandId.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getErrandVO = async (id: string) => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
// 修改参数传递方式为query params
|
||||||
|
const res: any = await myAxios.post('/errand/get/id', null, {
|
||||||
|
params: {
|
||||||
|
errandId1: id // 直接使用参数id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
errandInfo.value = res.data || {};
|
||||||
|
state.value = res.data.state ?? 0;
|
||||||
|
}else if(res.code===40000){
|
||||||
|
message.error(res.description);
|
||||||
|
router.go(-1)
|
||||||
|
}else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching data:", error);
|
||||||
|
message.error('请求过程中出现错误,请稍后再试');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = async (newState: number) => {
|
||||||
|
try {
|
||||||
|
// 构建请求体,仅包含'id'和'state'
|
||||||
|
const requestBody = {
|
||||||
|
id: errandId.value || '',
|
||||||
|
state: newState,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res: any = await myAxios.post("/errand/update", requestBody, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json', // 修改为JSON格式,如果你的后端接受JSON的话
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.code === 0) {
|
||||||
|
message.success("已审核");
|
||||||
|
state.value = newState; // 更新本地状态
|
||||||
|
} else {
|
||||||
|
message.error(`审核失败:${res.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("更新状态失败:", error);
|
||||||
|
message.error('请求过程中出现错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
228
CampusExpressDelivery/src/view/errand/errandList.vue
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<div class="search-box">
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-space>
|
||||||
|
<a-form-item label="快送员名称">
|
||||||
|
<a-input-search
|
||||||
|
style="width: 300px"
|
||||||
|
placeholder="请输入快送员名称"
|
||||||
|
enter-button
|
||||||
|
allow-clear
|
||||||
|
@search="onSearch"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="状态">
|
||||||
|
<a-select
|
||||||
|
style="width: 200px;"
|
||||||
|
placeholder="默认查询全部状态"
|
||||||
|
allowClear
|
||||||
|
v-model:value="searchParams.state"
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
|
<a-select-option value="">全部</a-select-option>
|
||||||
|
<a-select-option value="0">未审核</a-select-option>
|
||||||
|
<a-select-option value="1">已审核</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="手机号">
|
||||||
|
<a-input-search
|
||||||
|
style="width: 300px"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
enter-button
|
||||||
|
allow-clear
|
||||||
|
@search="onSearchPhone"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1500, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="false"
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'errandAvatarUrl'">
|
||||||
|
<a-avatar :src="record.errandAvatarUrl"/>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'state'">
|
||||||
|
<div v-if="record.state === 0">
|
||||||
|
<a-tag color="orange">未审核</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 1">
|
||||||
|
<a-tag color="green">已审核</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 2">
|
||||||
|
<a-tag color="red">封禁</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button v-if="record.state === 0" size="small" type="link" @click="toInfoPage(record.id)">审核</a-button>
|
||||||
|
<a-button v-else size="small"
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(255, 141, 26, 1);"
|
||||||
|
@click="toInfoPage(record.id)">查看
|
||||||
|
</a-button>
|
||||||
|
<a-button :disabled="record.state === 0" size="small" type="link" danger
|
||||||
|
@click="doBan(record.id, record.state === 1)">
|
||||||
|
{{ record.state === 1 ? '禁用' : '启用' }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<!-- 分页部分 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="searchParams.current"
|
||||||
|
v-model:pageSize="searchParams.pageSize"
|
||||||
|
show-quick-jumper
|
||||||
|
show-size-changer
|
||||||
|
:show-total="(total: any) => `共 ${total} 个快送员`"
|
||||||
|
:total="total"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import myAxios from "../../api/myAxios";
|
||||||
|
import { formatTime } from "../../utils/TableConfig";
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
|
import router from "../../router";
|
||||||
|
|
||||||
|
const tableData: any = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
// 分页
|
||||||
|
const total: any = ref(0);
|
||||||
|
// 请求参数
|
||||||
|
const searchParams: any = ref({
|
||||||
|
sortField: "createTime",
|
||||||
|
sortOrder: "descend",
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
errandName: "",
|
||||||
|
state: "", // 默认为空,表示查询所有状态
|
||||||
|
errandPhone:""
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ index }: any) => {
|
||||||
|
return `${(searchParams.value.current - 1) * searchParams.value.pageSize + index + 1}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ title: '快送员名称', dataIndex: 'errandName', width: 100, fixed: 'left', align: 'center' },
|
||||||
|
{ title: '快送员头像', key: 'errandAvatarUrl', width: 50, align: 'center' },
|
||||||
|
{ title: '手机号', dataIndex: 'errandPhone', width: 150, align: 'center' },
|
||||||
|
{ title: '状态', key: 'state', width: 70, align: 'center' },
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
width: 150,
|
||||||
|
align: 'center',
|
||||||
|
customRender: (row: any) => {
|
||||||
|
return formatTime(row);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ title: '操作', key: '操作', fixed: 'right', width: 100, align: 'center' },
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面加载时,请求数据
|
||||||
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
getErrandList(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取快送员数据
|
||||||
|
*/
|
||||||
|
const getErrandList = async (current: number) => {
|
||||||
|
searchParams.value.current = current;
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post("/errand/page", { ...searchParams.value });
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
tableData.value = res.data.records;
|
||||||
|
total.value = parseInt(res.data.total);
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作
|
||||||
|
*/
|
||||||
|
const doBan = async (id: string, isBan: boolean) => {
|
||||||
|
const res: any = await myAxios.post("/errand/update", { id: id, state: isBan ? 2 : 1 });
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
message.success(`操作成功`);
|
||||||
|
await getErrandList(1);
|
||||||
|
} else {
|
||||||
|
message.error(`封禁商家失败:${res.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索功能
|
||||||
|
*/
|
||||||
|
const onSearch = (errandName: string) => {
|
||||||
|
searchParams.value.errandName = errandName;
|
||||||
|
searchParams.value.current = 1;
|
||||||
|
getErrandList(1);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 搜索功能
|
||||||
|
*/
|
||||||
|
const onSearchPhone = (errandPhone: string) => {
|
||||||
|
searchParams.value.errandPhone = errandPhone;
|
||||||
|
searchParams.value.current = 1;
|
||||||
|
getErrandList(1);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
const onChange = (pageNumber: number) => {
|
||||||
|
searchParams.value.current = pageNumber;
|
||||||
|
getErrandList(pageNumber);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转到快送员信息
|
||||||
|
*/
|
||||||
|
const toInfoPage = (id: string) => {
|
||||||
|
console.log(id); // 打印传递的ID值
|
||||||
|
router.push({
|
||||||
|
name: '快送员审核',
|
||||||
|
// path: '/errandInfo',
|
||||||
|
query: {
|
||||||
|
id: String(id) // 确保ID值是字符串类型
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当状态选择器值改变时触发
|
||||||
|
*/
|
||||||
|
const handleChange = () => {
|
||||||
|
getErrandList(1);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
371
CampusExpressDelivery/src/view/errand/errandOrderList.vue
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<a-button style="margin-bottom: 30px" type="primary" @click="back">返回</a-button>
|
||||||
|
快送员订单
|
||||||
|
<div class="data-box">
|
||||||
|
<div style="display: flex;justify-content: space-around">
|
||||||
|
<a-descriptions :column=3 style="width: 85%">
|
||||||
|
<a-descriptions-item label="快送员姓名">{{ errandData?.errandName }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="配送单位">{{ errandData?.distributionScope }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="联系方式">{{ errandData?.errandPhone }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="银行卡号">{{ errandData?.bankCard }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="当前接单量">{{ errandData?.totalOrders }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="最大送单量">{{ errandData?.maxOrders }}</a-descriptions-item>
|
||||||
|
</a-descriptions>
|
||||||
|
<div style="width: 15%;display: flex;white-space: nowrap">
|
||||||
|
图片:
|
||||||
|
<div style="width: 45%">
|
||||||
|
<a-image :src="errandData.errandAvatarUrl"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-box" style="margin-top: 2%;display: inline-block;width: 100%">
|
||||||
|
<div style="display: flex;justify-content: space-between;margin-bottom: 2%">
|
||||||
|
<!-- 查询信息 -->
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-space>
|
||||||
|
<a-input-search
|
||||||
|
style="width: 400px"
|
||||||
|
placeholder="请输入订单号"
|
||||||
|
enter-button
|
||||||
|
allow-clear
|
||||||
|
@search="onSearch"
|
||||||
|
/>
|
||||||
|
<a-select
|
||||||
|
v-model:value="searchParams.state"
|
||||||
|
style="width: 120px"
|
||||||
|
@change="getOrdersList(1)"
|
||||||
|
>
|
||||||
|
<a-select-option value="">全部</a-select-option>
|
||||||
|
<a-select-option value="0">未支付</a-select-option>
|
||||||
|
<a-select-option value="1">已支付</a-select-option>
|
||||||
|
<a-select-option value="2">已退款</a-select-option>
|
||||||
|
<a-select-option value="3">已取消</a-select-option>
|
||||||
|
<a-select-option value="4">已出餐</a-select-option>
|
||||||
|
<a-select-option value="5">已完成</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
<a-space>
|
||||||
|
<!-- 导出信息 -->
|
||||||
|
<a-button type="primary" @click="download">EXCEL导出</a-button>
|
||||||
|
<!--筛选时间-->
|
||||||
|
<a-range-picker @change="searchTime" format="YYYY-MM-DD"/>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 800, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:rowKey="(record: any) => record.id"
|
||||||
|
:pagination=false
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'state'">
|
||||||
|
<div v-if="record.state === 0">
|
||||||
|
<a-tag color="purple">未支付</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 1">
|
||||||
|
<a-tag color="blue">已支付</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 2">
|
||||||
|
<a-tag color="red">已退款</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 3">
|
||||||
|
<a-tag color="gray">已取消</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 4">
|
||||||
|
<a-tag color="blue">已出餐</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 5">
|
||||||
|
<a-tag color="green">已完成</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'totalPrice'">
|
||||||
|
<a-tag color="purple">{{ record.totalPrice }}</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button size="small"
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(255, 141, 26, 1);"
|
||||||
|
@click="router.push({path:'/orderDetail',query:{id:record.id}})">查看
|
||||||
|
</a-button>
|
||||||
|
<a-button v-if="[1, 4, 5].includes(record.state)"
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(255, 141, 26, 1);"
|
||||||
|
@click="modalOpen = true; recordId=record.orderNo">退款
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
<!--订单金额信息 -->
|
||||||
|
<div style="margin: 20px 0 20px 0;float: left;">
|
||||||
|
<span class="ant-pagination-total-text">总金额:{{ ordersCount }}元</span>
|
||||||
|
</div>
|
||||||
|
<!-- 分页部分 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="searchParams.current"
|
||||||
|
v-model:pageSize="searchParams.pageSize"
|
||||||
|
show-size-changer
|
||||||
|
show-quick-jumper
|
||||||
|
:total="total"
|
||||||
|
:show-total="() => `共 ${total} 条订单`"
|
||||||
|
@change="onChange"
|
||||||
|
@showSizeChange="onShowSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!--退款弹出框-->
|
||||||
|
<a-modal v-model:open="modalOpen" title="退款" destroyOnClose @ok="refund()">
|
||||||
|
<span>确定退款吗</span>
|
||||||
|
</a-modal>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {formatTime} from "../../utils/TableConfig";
|
||||||
|
import router from "../../router";
|
||||||
|
import myAxios from "../../api/myAxios.ts";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
//订单信息
|
||||||
|
const tableData: any = ref([])
|
||||||
|
//店铺信息
|
||||||
|
const errandData: any = ref({})
|
||||||
|
//订单总金额
|
||||||
|
const ordersCount: any = ref<Number>()
|
||||||
|
//加载按钮
|
||||||
|
const loading = ref(false)
|
||||||
|
//弹出框开关
|
||||||
|
const modalOpen = ref<boolean>(false);
|
||||||
|
//退款id
|
||||||
|
const recordId = ref<Number>();
|
||||||
|
// 分页
|
||||||
|
const total: any = ref(0);
|
||||||
|
//查询条件
|
||||||
|
const searchParams: any = ref({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
orderId: null,
|
||||||
|
searchTime: null,
|
||||||
|
state: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{title: '订单号', dataIndex: 'id', key: 'id', width: 100, fixed: 'left', align: 'center'},
|
||||||
|
{
|
||||||
|
title: '下单时间', dataIndex: 'createTime', key: 'createTime', width: 100, align: 'center',
|
||||||
|
customRender: (row: any) => {
|
||||||
|
return formatTime(row)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '卖家昵称', dataIndex: 'userName', key: 'userName', width: 150, align: 'center'},
|
||||||
|
{title: '支付状态', dataIndex: 'state', key: 'state', width: 150, align: 'center'},
|
||||||
|
{title: '订单金额', dataIndex: 'totalPrice', key: 'totalPrice', width: 150, align: 'center'},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 80, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getOrdersList(1)
|
||||||
|
getBusinessVO()
|
||||||
|
getOrdersCount()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取订单信息列表
|
||||||
|
*/
|
||||||
|
console.log(route.query.id)
|
||||||
|
const getOrdersList = async (current: any) => {
|
||||||
|
let errandId = route.query.id; //商家id
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post('/orders/list/page', {
|
||||||
|
errandId: errandId,
|
||||||
|
businessId: "",
|
||||||
|
current: current,
|
||||||
|
pageSize: searchParams.value.pageSize,
|
||||||
|
id: searchParams.value.orderId,
|
||||||
|
sortField: "createTime",
|
||||||
|
sortOrder: "descend",
|
||||||
|
state: searchParams.value.state,
|
||||||
|
startTime: searchParams.value.searchTime == null ? '' : searchParams.value.searchTime[0],
|
||||||
|
endTime: searchParams.value.searchTime == null ? '' : searchParams.value.searchTime[1]
|
||||||
|
})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
searchParams.value.current = current
|
||||||
|
tableData.value = res.data.records;
|
||||||
|
total.value = parseInt(res.data.total);
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
console.log("没有获取订单")
|
||||||
|
console.log(res.data)
|
||||||
|
message.error(`获取数据失败:${res.description}`);
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取店铺信息
|
||||||
|
*/
|
||||||
|
const getBusinessVO = async () => {
|
||||||
|
let errandId:any = route.query.id;
|
||||||
|
if (!errandId) {
|
||||||
|
console.error("商家ID未定义或为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new URLSearchParams();
|
||||||
|
formData.append('errandId1', errandId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res:any = await myAxios.post('/errand/get/id', formData.toString(), {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
console.log(res)
|
||||||
|
errandData.value = res.data;
|
||||||
|
} else {
|
||||||
|
console.log(res)
|
||||||
|
message.error(`获取数据失败:${res.description}`);
|
||||||
|
back();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('请求异常:', error);
|
||||||
|
message.error('接口请求异常,请检查控制台');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取该店铺收入
|
||||||
|
*/
|
||||||
|
const getOrdersCount = async () => {
|
||||||
|
let errandId = route.query.id; //商家id
|
||||||
|
const res: any = await myAxios.post('/orders/count', {
|
||||||
|
"errandId": errandId,
|
||||||
|
"type": "money",
|
||||||
|
"state": 5
|
||||||
|
})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
console.log(res)
|
||||||
|
ordersCount.value = res.data;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.description}`);
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出Excel表
|
||||||
|
*/
|
||||||
|
const download = async () => {
|
||||||
|
let errandId = route.query.id //商家id
|
||||||
|
const res: any = await myAxios.post('/orders/download/errand', {
|
||||||
|
errandId: errandId,
|
||||||
|
// 添加时间参数(与列表查询保持一致)
|
||||||
|
startTime: searchParams.value.searchTime?.[0] || '',
|
||||||
|
endTime: searchParams.value.searchTime?.[1] || '',
|
||||||
|
// 保留其他必要参数
|
||||||
|
current: searchParams.value.current,
|
||||||
|
pageSize: searchParams.value.pageSize,
|
||||||
|
sortField: "createTime",
|
||||||
|
sortOrder: "descend"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
responseType: "blob"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
downloadCallback(res, '快送员订单信息表.xlsx')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款
|
||||||
|
*/
|
||||||
|
// const refund = async () => {
|
||||||
|
// const res: any = await myAxios.get('/Alipay/test/refund', {orderNo: recordId.value})
|
||||||
|
// if (res.code === 0 && res.data) {
|
||||||
|
// message.success('退款成功');
|
||||||
|
// modalOpen.value = false
|
||||||
|
// await getOrdersList(1)
|
||||||
|
// await getOrdersCount()
|
||||||
|
// } else {
|
||||||
|
// message.error(`退款失败:${res.description}`);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
const refund = async () => {
|
||||||
|
const res: any = await myAxios.get(`/Alipay/test/refund?orderNo=${recordId.value}`);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
message.success('退款成功');
|
||||||
|
modalOpen.value = false;
|
||||||
|
await getOrdersList(1);
|
||||||
|
await getOrdersCount();
|
||||||
|
} else {
|
||||||
|
message.error(`退款失败:${res.description}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 查询
|
||||||
|
*/
|
||||||
|
const onSearch = async (ordersId: number) => {
|
||||||
|
searchParams.value.orderId = ordersId
|
||||||
|
await getOrdersList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询时间
|
||||||
|
*/
|
||||||
|
const searchTime = async (dateTime: any) => {
|
||||||
|
searchParams.value.searchTime = dateTime
|
||||||
|
await getOrdersList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
const onShowSizeChange = (current: number, pageSize: number) => {
|
||||||
|
searchParams.value.pageSize = pageSize;
|
||||||
|
getOrdersList(current);
|
||||||
|
}
|
||||||
|
const onChange = (pageNumber: number) => {
|
||||||
|
searchParams.value.current = pageNumber;
|
||||||
|
getOrdersList(pageNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回
|
||||||
|
*/
|
||||||
|
const back = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
//生成下载文件
|
||||||
|
const downloadCallback = (res: any, fileName: any) => {
|
||||||
|
const blob = new Blob([res]);
|
||||||
|
if ("download" in document.createElement("a")) {
|
||||||
|
// 非IE下载
|
||||||
|
const elink = document.createElement("a");
|
||||||
|
elink.download = fileName;
|
||||||
|
elink.style.display = "none";
|
||||||
|
elink.href = URL.createObjectURL(blob);
|
||||||
|
document.body.appendChild(elink);
|
||||||
|
elink.click();
|
||||||
|
URL.revokeObjectURL(elink.href); // 释放URL 对象
|
||||||
|
document.body.removeChild(elink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
177
CampusExpressDelivery/src/view/errand/runList.vue
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<div class="search-box">
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-space warp>
|
||||||
|
<a-form-item
|
||||||
|
label="快送员名"
|
||||||
|
>
|
||||||
|
<a-input allow-clear @change="change" @pressEnter="getBusinessList(1)"
|
||||||
|
v-model:value="searchParams.errandName"
|
||||||
|
placeholder="请输入快送员名"/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="配送范围">
|
||||||
|
<a-select
|
||||||
|
style="width: 200px;"
|
||||||
|
placeholder="默认查询全部快送员"
|
||||||
|
allowClear
|
||||||
|
v-model:value="searchParams.distributionScope"
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
|
<a-select-option value='1公寓'>1公寓</a-select-option>
|
||||||
|
<a-select-option value='2公寓'>2公寓</a-select-option>
|
||||||
|
<a-select-option value='3公寓'>3公寓</a-select-option>
|
||||||
|
<a-select-option value='4公寓'>4公寓</a-select-option>
|
||||||
|
<a-select-option value='5公寓'>5公寓</a-select-option>
|
||||||
|
<a-select-option value='6公寓'>6公寓</a-select-option>
|
||||||
|
<a-select-option value='7公寓'>7公寓</a-select-option>
|
||||||
|
<a-select-option value='8公寓'>8公寓</a-select-option>
|
||||||
|
<a-select-option value='9公寓'>9公寓</a-select-option>
|
||||||
|
<a-select-option value='10公寓'>10公寓</a-select-option>
|
||||||
|
<a-select-option value='11公寓'>11公寓</a-select-option>
|
||||||
|
<a-select-option value='12公寓'>12公寓</a-select-option>
|
||||||
|
<a-select-option value='育才大厦'>育才大厦</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-button type="primary" @click="getBusinessList(1)">查询</a-button>
|
||||||
|
<a-button @click="reset">重置</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1000, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination=false
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'businessAvatar'">
|
||||||
|
<a-avatar :src="record.errandAvatarUrl"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button size="small"
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(255, 141, 26, 1);"
|
||||||
|
@click="router.push({path: '/errandOrderList',query: {id: record.id}})">查看
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<!-- 分页部分 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="searchParams.current"
|
||||||
|
v-model:pageSize="searchParams.pageSize"
|
||||||
|
show-quick-jumper
|
||||||
|
show-size-changer
|
||||||
|
:show-total="(total: any) => `共 ${total} 位快送员`"
|
||||||
|
:total="total"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import myAxios from "../../api/myAxios";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import router from "../../router";
|
||||||
|
|
||||||
|
//表单数据
|
||||||
|
const tableData: any = ref([]);
|
||||||
|
//加载按钮
|
||||||
|
const loading = ref(false)
|
||||||
|
// 分页
|
||||||
|
const total: any = ref(0);
|
||||||
|
//查询条件
|
||||||
|
const searchParams: any = ref({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
errandName: '',
|
||||||
|
distributionScope: null
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({index}: any) => {
|
||||||
|
return `${(searchParams.value.current - 1) * searchParams.value.pageSize + index + 1}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '图片', dataIndex: 'businessAvatar', key: 'businessAvatar', width: 50, align: 'center'},
|
||||||
|
{title: '快送员名', dataIndex: 'errandName', key: 'errandName', width: 50, align: 'center'},
|
||||||
|
{title: '当前接单量', dataIndex: 'totalOrders', key: 'totalOrders', width: 50, align: 'center'},
|
||||||
|
{title: '最大接单量', dataIndex: 'maxOrders', key: 'maxOrders', width: 50, align: 'center'},
|
||||||
|
{title: '配送范围', dataIndex: 'distributionScope', key: 'distributionScope', width: 50, align: 'center'},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 50, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getBusinessList(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商家信息列表
|
||||||
|
*/
|
||||||
|
const getBusinessList = async (current: number) => {
|
||||||
|
searchParams.value.current = current
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post('/errand/page', {...searchParams.value})
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
tableData.value = res.data.records;
|
||||||
|
total.value = parseInt(res.data.total);
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择用户身份
|
||||||
|
*/
|
||||||
|
const handleChange = (distributionScope: string) => {
|
||||||
|
searchParams.value.distributionScope = distributionScope;
|
||||||
|
getBusinessList(1)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置查询条件
|
||||||
|
*/
|
||||||
|
const reset = () => {
|
||||||
|
searchParams.value.errandName = ''
|
||||||
|
searchParams.value.distributionScope = null
|
||||||
|
getBusinessList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
const onChange = (pageNumber: number) => {
|
||||||
|
searchParams.value.current = pageNumber;
|
||||||
|
getBusinessList(pageNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除输入框的回调
|
||||||
|
*/
|
||||||
|
const change = (row: any) => {
|
||||||
|
if (row.type === 'click') getBusinessList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
169
CampusExpressDelivery/src/view/shop/BusinessLog.vue
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<div class="search-box">
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-space>
|
||||||
|
<a-form-item label="手机号">
|
||||||
|
<a-input-search
|
||||||
|
style="width: 300px"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
enter-button
|
||||||
|
allow-clear
|
||||||
|
@search="onSearchByPhone"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1500, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination=false
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'businessAvatar'">
|
||||||
|
<a-avatar v-if="record.business!=null" :src="record?.business.businessAvatar"/>
|
||||||
|
<div v-else>
|
||||||
|
<a-tag color="blue">Boss账号</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'businessName'">
|
||||||
|
<div v-if="record.business!=null">{{ record?.business.businessName }}</div>
|
||||||
|
<div v-else>
|
||||||
|
<a-tag color="blue">Boss账 号</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'businessPhone'">
|
||||||
|
<div v-if="record.business!=null">{{ record?.business.businessPhone }}</div>
|
||||||
|
<div v-else>
|
||||||
|
<a-tag color="blue">Boss账号</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'content'">
|
||||||
|
<a-tag :color="getTagColor(record.content)">{{ record.content }}</a-tag>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<!-- 分页部分 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="searchParams.current"
|
||||||
|
v-model:pageSize="searchParams.pageSize"
|
||||||
|
show-quick-jumper
|
||||||
|
show-size-changer
|
||||||
|
:show-total="(total: any) => `共 ${total} 条数据`"
|
||||||
|
:total="total"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {formatTime} from "../../utils/TableConfig";
|
||||||
|
import myAxios from "../../api/myAxios";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
|
||||||
|
const getTagColor = (content: string) => {
|
||||||
|
const blueOperations = ['修改菜品', '修改菜品分组'];
|
||||||
|
const redOperations = [ '删除菜品', '删除菜品分组'];
|
||||||
|
const greenOperations = ['添加菜品', '添加菜品分组'];
|
||||||
|
|
||||||
|
if (blueOperations.includes(content)) return 'blue';
|
||||||
|
if (greenOperations.includes(content)) return 'green';
|
||||||
|
if (redOperations.includes(content)) return 'red';
|
||||||
|
return 'red'; // 其他操作保持红色
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableData: any = ref([]);
|
||||||
|
const loading = ref(false)
|
||||||
|
// 分页
|
||||||
|
const total: any = ref(0);
|
||||||
|
// 请求参数
|
||||||
|
const searchParams: any = ref({
|
||||||
|
sortField: "createTime",
|
||||||
|
sortOrder: "descend",
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
businessPhone: '',
|
||||||
|
startTime: '',
|
||||||
|
endTime: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({index}: any) => {
|
||||||
|
return `${(searchParams.value.current - 1) * searchParams.value.pageSize + index + 1}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '门店名称', key: 'businessName', width: 100, align: 'center'},
|
||||||
|
{title: '门店头像', key: 'businessAvatar', width: 50, align: 'center'},
|
||||||
|
{title: '手机号', key: 'businessPhone', width: 150, align: 'center'},
|
||||||
|
{title: '执行操作', key: 'content', width: 150, align: 'center'},
|
||||||
|
{title: 'ip地址', dataIndex: 'ip', key: 'ip', width: 150, align: 'center'},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
width: 150,
|
||||||
|
align: 'center',
|
||||||
|
customRender: (row: any) => {
|
||||||
|
return formatTime(row)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面加载时,请求数据
|
||||||
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
getBusinessLogList();
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商家操作日志
|
||||||
|
*/
|
||||||
|
const getBusinessLogList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post("/log/business/logs", {...searchParams.value})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
tableData.value = res.data.records;
|
||||||
|
total.value = parseInt(res.data.total);
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据手机号搜索功能
|
||||||
|
*/
|
||||||
|
const onSearchByPhone = (businessPhone: number) => {
|
||||||
|
searchParams.value.businessPhone = businessPhone;
|
||||||
|
searchParams.value.current = 1;
|
||||||
|
getBusinessLogList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
const onChange = (pageNumber: number) => {
|
||||||
|
searchParams.value.current = pageNumber;
|
||||||
|
getBusinessLogList();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
155
CampusExpressDelivery/src/view/shop/business/BusinessInfo.vue
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<template>
|
||||||
|
<a-card title="商家信息" :loading="loading">
|
||||||
|
<div class="main-card" >
|
||||||
|
<a-descriptions size="default" bordered class="txt">
|
||||||
|
<a-descriptions-item label="头像">
|
||||||
|
<template v-slot>
|
||||||
|
<a-avatar :src="businessInfo.businessAvatar" style="width: 100px;height: 100px;"/>
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="店铺名称">{{ businessInfo?.businessName }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="店主姓名">{{ businessInfo?.shopkeeper }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="联系方式">{{ businessInfo?.businessPhone }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="店铺地址">{{ businessInfo.address }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="银行卡号">{{ businessInfo?.bankCard }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="营业执照">
|
||||||
|
<template v-slot>
|
||||||
|
<a-image :src="businessInfo.license" style="width: 158.5px; height: 100px;"/>
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="身份证正面">
|
||||||
|
<template v-slot>
|
||||||
|
<a-image :src="businessInfo.frontIdCard" style="width: 158.5px; height: 100px;"/>
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="身份证反面">
|
||||||
|
<template v-slot>
|
||||||
|
<a-image :src="businessInfo.backIdCard" style="width: 158.5px; height: 100px"/>
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="当前状态">
|
||||||
|
<div v-if="businessInfo.state === 0">
|
||||||
|
<a-tag color="orange">未审核</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="businessInfo.state === 1">
|
||||||
|
<a-tag color="green">正常营业</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="businessInfo.state === 2">
|
||||||
|
<a-tag color="red">暂定营业</a-tag>
|
||||||
|
</div>
|
||||||
|
</a-descriptions-item>
|
||||||
|
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'businessAvatar'">
|
||||||
|
<a-avatar :src="record.businessAvatar"/>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'license'">
|
||||||
|
<a-image :src="record.license" style="width: 100px;height: 100px;"></a-image>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'frontIdCard'">
|
||||||
|
<a-image :src="record.frontIdCard" style="width: 100px;height: 100px;"></a-image>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'backIdCard'">
|
||||||
|
<a-image :src="record.backIdCard" style="width: 100px;height: 100px;"></a-image>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'state'">
|
||||||
|
<div v-if="record.state === 0">
|
||||||
|
<a-tag color="orange">未审核</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 1">
|
||||||
|
<a-tag color="green">已通过</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 2">
|
||||||
|
<a-tag color="red">未通过</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-descriptions>
|
||||||
|
</div>
|
||||||
|
<a-space>
|
||||||
|
<div class="button-box">
|
||||||
|
<a-button
|
||||||
|
class="button-s"
|
||||||
|
size="small"
|
||||||
|
type="default"
|
||||||
|
style="color: blue"
|
||||||
|
@click="backPage">返回
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
class="button-s"
|
||||||
|
size="small" v-if="state === 0"
|
||||||
|
type="primary"
|
||||||
|
style="color: white; margin-left: 15px"
|
||||||
|
danger
|
||||||
|
@click="update(2)">未通过
|
||||||
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
class="button-s"
|
||||||
|
size="small" v-if="state === 0"
|
||||||
|
type="primary"
|
||||||
|
style="color: white; margin-left: 15px"
|
||||||
|
@click="update(1)">通过
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</a-space>
|
||||||
|
</a-card>
|
||||||
|
<!-- 菜品列表展示区 -->
|
||||||
|
<a-divider />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import myAxios from "../../../api/myAxios";
|
||||||
|
import {backPage} from "../../../utils/TableConfig";
|
||||||
|
|
||||||
|
const state = ref(0)
|
||||||
|
const route = useRoute();
|
||||||
|
const loading = ref(false);
|
||||||
|
const businessInfo: any = ref({});
|
||||||
|
const businessId = route.query.businessId; //商家id
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getBusinessVO();
|
||||||
|
// listDishGroup();
|
||||||
|
})
|
||||||
|
|
||||||
|
const getBusinessVO = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.get('/business/getById', {params: {"id": businessId}})
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
businessInfo.value = res.data;
|
||||||
|
state.value = res.data.state
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
backPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = async (state: number) => {
|
||||||
|
const res: any = await myAxios.post("/business/update", {id: businessId, state: state})
|
||||||
|
if (res.code === 0) {
|
||||||
|
message.success("已审核")
|
||||||
|
} else {
|
||||||
|
message.error(`审核失败:${res.description}`);
|
||||||
|
}
|
||||||
|
backPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.button-box {
|
||||||
|
margin: 100px 0 500px 1100px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
.button-s {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
203
CampusExpressDelivery/src/view/shop/business/BusinessManage.vue
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<div class="search-box">
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-space>
|
||||||
|
<a-form-item label="门店名称">
|
||||||
|
<a-input-search
|
||||||
|
style="width: 300px"
|
||||||
|
placeholder="请输入门店名称"
|
||||||
|
enter-button
|
||||||
|
allow-clear
|
||||||
|
@search="onSearch"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1500, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination=false
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'businessAvatar'">
|
||||||
|
<a-avatar :src="record.businessAvatar"/>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'state'">
|
||||||
|
<div v-if="record.state === 0">
|
||||||
|
<a-tag color="orange">未审核</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 1">
|
||||||
|
<a-tag color="green">正常营业</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 2">
|
||||||
|
<a-tag color="red">封禁</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button v-if="record.state === 0" size="small" type="link" @click="toInfoPage(record.id)">审核</a-button>
|
||||||
|
<a-button v-else size="small"
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(255, 141, 26, 1);"
|
||||||
|
@click="toInfoPage(record.id)">查看
|
||||||
|
</a-button>
|
||||||
|
<a-button :disabled="record.state === 0" size="small" type="link" danger
|
||||||
|
@click="doBan(record.id, record.state === 1)">
|
||||||
|
{{ record.state === 1 ? '禁用' : '启用' }}
|
||||||
|
</a-button>
|
||||||
|
<a-button type="link"
|
||||||
|
style="color: rgba(71, 214, 213);"
|
||||||
|
@click="toDishGroupPage(record.id)">查看菜品
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<!-- 分页部分 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="searchParams.current"
|
||||||
|
v-model:pageSize="searchParams.pageSize"
|
||||||
|
show-quick-jumper
|
||||||
|
show-size-changer
|
||||||
|
:show-total="(total: any) => `共 ${total} 家店铺`"
|
||||||
|
:total="total"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import myAxios from "../../../api/myAxios";
|
||||||
|
import {formatTime} from "../../../utils/TableConfig";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import router from "../../../router";
|
||||||
|
|
||||||
|
const tableData: any = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
// 分页
|
||||||
|
const total: any = ref(0);
|
||||||
|
// 请求参数
|
||||||
|
const searchParams: any = ref({
|
||||||
|
sortField: "createTime",
|
||||||
|
sortOrder: "descend",
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
businessName: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({index}: any) => {
|
||||||
|
return `${(searchParams.value.current - 1) * searchParams.value.pageSize + index + 1}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '门店名称', dataIndex: 'businessName', width: 100, fixed: 'left', align: 'center'},
|
||||||
|
{title: '门店头像', key: 'businessAvatar', width: 50, align: 'center'},
|
||||||
|
{title: '手机号', dataIndex: 'businessPhone', width: 150, align: 'center'},
|
||||||
|
{title: '状态', key: 'state', width: 70, align: 'center'},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
width: 150,
|
||||||
|
align: 'center',
|
||||||
|
customRender: (row: any) => {
|
||||||
|
return formatTime(row)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 100, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面加载时,请求数据
|
||||||
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
getBusinessList(1);
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商家数据
|
||||||
|
*/
|
||||||
|
const getBusinessList = async (current: number) => {
|
||||||
|
searchParams.value.current = current
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post("/business/list/page", {...searchParams.value})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
tableData.value = res.data.records;
|
||||||
|
total.value = parseInt(res.data.total);
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作
|
||||||
|
*/
|
||||||
|
const doBan = async (id: string, isBan: boolean) => {
|
||||||
|
const res: any = await myAxios.post("/business/update", {id: id, state: isBan ? 2 : 1})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
message.success(`操作成功`);
|
||||||
|
await getBusinessList(1);
|
||||||
|
} else {
|
||||||
|
message.error(`封禁商家失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索功能
|
||||||
|
*/
|
||||||
|
const onSearch = (businessName: string) => {
|
||||||
|
searchParams.value.businessName = businessName;
|
||||||
|
searchParams.value.current = 1;
|
||||||
|
getBusinessList(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
const onChange = (pageNumber: number) => {
|
||||||
|
searchParams.value.current = pageNumber;
|
||||||
|
getBusinessList(pageNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转到商家信息
|
||||||
|
*/
|
||||||
|
const toInfoPage = (businessId: any) => {
|
||||||
|
router.push({
|
||||||
|
name: '门店详情',
|
||||||
|
query: {
|
||||||
|
businessId: businessId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const toDishGroupPage = (businessId: any) => {
|
||||||
|
router.push({
|
||||||
|
name: '菜品分组详情',
|
||||||
|
query: {
|
||||||
|
businessId: businessId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
123
CampusExpressDelivery/src/view/shop/business/Dish.vue
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import myAxios from "../../../api/myAxios";
|
||||||
|
import {backPage} from "../../../utils/TableConfig";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const businessId = route.query.businessId;
|
||||||
|
const dishGroupId = route.query.dishGroupId;
|
||||||
|
const dishGroup = ref([]);
|
||||||
|
// const loading = ref(false);
|
||||||
|
const searchParams: any = ref({
|
||||||
|
businessId: businessId,
|
||||||
|
current: 1,
|
||||||
|
dishesGroupId: dishGroupId,
|
||||||
|
dishesName: "",
|
||||||
|
pageSize: 10,
|
||||||
|
sortField: "",
|
||||||
|
sortOrder: "",
|
||||||
|
status: ""
|
||||||
|
})
|
||||||
|
const getDishGroup = async () => {
|
||||||
|
console.log(businessId);
|
||||||
|
try {
|
||||||
|
// loading.value = true;
|
||||||
|
const res: any = await myAxios.post('/dishes/list/dishes', {
|
||||||
|
...searchParams.value
|
||||||
|
})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
console.log(res)
|
||||||
|
dishGroup.value = res.data
|
||||||
|
} else {
|
||||||
|
message.error(res.description)
|
||||||
|
backPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
message.error("请求失败,请检查网络或后端服务");
|
||||||
|
backPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '菜品名称',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'dishesName',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '菜品图片',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
key: 'dishesImage',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '菜品价格',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'dishesPrice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '菜品打包费',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'packPrice',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
customRender: ({ text }: { text: string }) => text ? dayjs(text).format('YYYY-MM-DD') : '-',
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getDishGroup();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1500, y: 1000 }"
|
||||||
|
:data-source="dishGroup"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination=false
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'dishesImage'">
|
||||||
|
<a-avatar :src="record.dishesImage"></a-avatar>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<a-button
|
||||||
|
class="button-s"
|
||||||
|
size="small"
|
||||||
|
type="default"
|
||||||
|
style="color: blue"
|
||||||
|
@click="backPage">返回
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
109
CampusExpressDelivery/src/view/shop/business/DishGroup.vue
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import myAxios from "../../../api/myAxios";
|
||||||
|
import {backPage} from "../../../utils/TableConfig";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import router from "../../../router";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const businessId = route.query.businessId;
|
||||||
|
const dishGroup = ref([]);
|
||||||
|
// const loading = ref(false);
|
||||||
|
const getDishGroup = async () => {
|
||||||
|
console.log(businessId);
|
||||||
|
try {
|
||||||
|
// loading.value = true;
|
||||||
|
const res: any = await myAxios.post('/dishesGroup/list/dishesGroup', {
|
||||||
|
businessId: businessId,
|
||||||
|
})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
console.log(res)
|
||||||
|
dishGroup.value = res.data
|
||||||
|
} else {
|
||||||
|
message.error(res.description)
|
||||||
|
backPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
message.error("请求失败,请检查网络或后端服务");
|
||||||
|
backPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '菜品分组名称',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'groupName',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
customRender: ({ text }: { text: string }) => text ? dayjs(text).format('YYYY-MM-DD') : '-',
|
||||||
|
},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 100, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
const toDishPage = (businessId: any, dishGroupId:any) => {
|
||||||
|
router.push({
|
||||||
|
name: '菜品详情',
|
||||||
|
query: {
|
||||||
|
businessId: businessId,
|
||||||
|
dishGroupId: dishGroupId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getDishGroup();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1500, y: 1000 }"
|
||||||
|
:data-source="dishGroup"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="false"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(71, 214, 213);"
|
||||||
|
@click="toDishPage(businessId, record.id)">查看菜品
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<a-button
|
||||||
|
class="button-s"
|
||||||
|
size="small"
|
||||||
|
type="default"
|
||||||
|
style="color: blue"
|
||||||
|
@click="backPage">返回
|
||||||
|
</a-button>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
102
CampusExpressDelivery/src/view/shop/order/OrderDetail.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<!--订单详情-->
|
||||||
|
<a-descriptions :column=2>
|
||||||
|
<a-descriptions-item>
|
||||||
|
<div style="display: flex;align-items: center">
|
||||||
|
<span>商家信息:</span>
|
||||||
|
<a-avatar :src="businessData.businessAvatar"/>
|
||||||
|
<span>{{ businessData?.businessName }}</span>
|
||||||
|
</div>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="取餐码">
|
||||||
|
<a-tag color="processing" v-if="orderData?.pickupCode">{{ orderData?.pickupCode }}</a-tag>
|
||||||
|
<a-tag color="red" v-else>暂未支付</a-tag>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="支付方式">
|
||||||
|
<div v-if="orderData.payMethod === 0">微信支付</div>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="用户电话">{{ orderData?.phone }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="支付金额">{{ orderData?.totalPrice }}元</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="订单编号">{{ orderData.id }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="下单时间">{{ orderData?.createTime }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="支付时间">{{ orderData?.updateTime }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="订单备注">{{ orderData?.notes }}</a-descriptions-item>
|
||||||
|
</a-descriptions>
|
||||||
|
<a-list :loading="loading" size="default" bordered :data-source="orderDetail">
|
||||||
|
<template #header>
|
||||||
|
<div>订单列表</div>
|
||||||
|
</template>
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<a-list-item style="display: flex">
|
||||||
|
<a-list-item-meta :description="item.attributeNames === '' ? '未选择规格' : item.attributeNames">
|
||||||
|
<template #title>
|
||||||
|
<div>{{ item.dishesVO.dishesName }}</div>
|
||||||
|
</template>
|
||||||
|
<template #avatar>
|
||||||
|
<a-image style="width: 4rem" :src="item.dishesVO.dishesImage"/>
|
||||||
|
</template>
|
||||||
|
</a-list-item-meta>
|
||||||
|
<a-list-item-meta style="display: flex; align-items: end">
|
||||||
|
<template #title>
|
||||||
|
<div style="float: right;margin-left: 10%">{{ item.subtotal }}元</div>
|
||||||
|
<div style="float: right">×{{ item.quantity }}</div>
|
||||||
|
</template>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
<a-button style="margin-top: 30px" type="primary" @click="back">返回</a-button>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import myAxios from "../../../api/myAxios";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import router from "../../../router";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
//加载按钮
|
||||||
|
const loading = ref(false);
|
||||||
|
//订单信息
|
||||||
|
const orderData: any = ref({});
|
||||||
|
//商家信息
|
||||||
|
const businessData: any = ref({});
|
||||||
|
//订单详情
|
||||||
|
const orderDetail: any = ref([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getOrderDetail()
|
||||||
|
})
|
||||||
|
|
||||||
|
const getOrderDetail = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.get('/orders/get', {
|
||||||
|
params: {id: route.query.id}
|
||||||
|
})
|
||||||
|
if (res.code === 0 && res.data)
|
||||||
|
{
|
||||||
|
console.log(res)
|
||||||
|
loading.value = false;
|
||||||
|
orderData.value = res.data
|
||||||
|
businessData.value = res.data.businessVO
|
||||||
|
orderDetail.value = res.data.orderDetailsVOList
|
||||||
|
orderData.value.createTime = orderData.value.createTime.slice(0, 16).replace('T', '~')
|
||||||
|
orderData.value.updateTime = orderData.value.updateTime.slice(0, 16).replace('T', '~')
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回
|
||||||
|
*/
|
||||||
|
const back = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
349
CampusExpressDelivery/src/view/shop/order/OrderList.vue
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<a-button style="margin-bottom: 30px" type="primary" @click="back">返回</a-button>
|
||||||
|
店铺信息
|
||||||
|
<div class="data-box">
|
||||||
|
<div style="display: flex;justify-content: space-around">
|
||||||
|
<a-descriptions :column=3 style="width: 85%">
|
||||||
|
<a-descriptions-item label="店铺名">{{ businessData?.businessName }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="店主姓名">{{ businessData?.shopkeeper }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="店铺地">{{ businessData.address }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="联系方式">{{ businessData?.businessPhone }}</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="银行卡号">{{ businessData?.bankCard }}</a-descriptions-item>
|
||||||
|
</a-descriptions>
|
||||||
|
<div style="width: 15%;display: flex;white-space: nowrap">
|
||||||
|
图片:
|
||||||
|
<div style="width: 45%">
|
||||||
|
<a-image :src="businessData.businessAvatar"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-box" style="margin-top: 2%;display: inline-block;width: 100%">
|
||||||
|
<div style="display: flex;justify-content: space-between;margin-bottom: 2%">
|
||||||
|
<!-- 查询信息 -->
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-space>
|
||||||
|
<a-input-search
|
||||||
|
style="width: 400px"
|
||||||
|
placeholder="请输入订单号"
|
||||||
|
enter-button
|
||||||
|
allow-clear
|
||||||
|
@search="onSearch"
|
||||||
|
/>
|
||||||
|
<a-select
|
||||||
|
v-model:value="searchParams.state"
|
||||||
|
style="width: 120px"
|
||||||
|
@change="getOrdersList(1)"
|
||||||
|
>
|
||||||
|
<a-select-option value="">全部</a-select-option>
|
||||||
|
<a-select-option value="0">未支付</a-select-option>
|
||||||
|
<a-select-option value="1">已支付</a-select-option>
|
||||||
|
<a-select-option value="2">已退款</a-select-option>
|
||||||
|
<a-select-option value="3">已取消</a-select-option>
|
||||||
|
<a-select-option value="4">已出餐</a-select-option>
|
||||||
|
<a-select-option value="5">已完成</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
<a-space>
|
||||||
|
<!-- 导出信息 -->
|
||||||
|
<a-button type="primary" @click="download">EXCEL导出</a-button>
|
||||||
|
<!--筛选时间-->
|
||||||
|
<a-range-picker @change="searchTime" format="YYYY-MM-DD"/>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 800, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:rowKey="(record: any) => record.id"
|
||||||
|
:pagination=false
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'state'">
|
||||||
|
<div v-if="record.state === 0">
|
||||||
|
<a-tag color="purple">未支付</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 1">
|
||||||
|
<a-tag color="blue">已支付</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 2">
|
||||||
|
<a-tag color="red">已退款</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 3">
|
||||||
|
<a-tag color="gray">已取消</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 4">
|
||||||
|
<a-tag color="blue">已出餐</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 5">
|
||||||
|
<a-tag color="green">已完成</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'totalPrice'">
|
||||||
|
<a-tag color="purple">{{ record.totalPrice }}</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button size="small"
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(255, 141, 26, 1);"
|
||||||
|
@click="router.push({path:'/orderDetail',query:{id:record.id}})">查看
|
||||||
|
</a-button>
|
||||||
|
<a-button v-if="record.state === 1"
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(255, 141, 26, 1);"
|
||||||
|
@click="modalOpen = true; recordId=record.orderNo">退款
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
<!--订单金额信息 -->
|
||||||
|
<div style="margin: 20px 0 20px 0;float: left;">
|
||||||
|
<span class="ant-pagination-total-text">总金额:{{ ordersCount }}元</span>
|
||||||
|
</div>
|
||||||
|
<!-- 分页部分 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="searchParams.current"
|
||||||
|
v-model:pageSize="searchParams.pageSize"
|
||||||
|
show-size-changer
|
||||||
|
show-quick-jumper
|
||||||
|
:total="total"
|
||||||
|
:show-total="() => `共 ${total} 条订单`"
|
||||||
|
@change="onChange"
|
||||||
|
@showSizeChange="onShowSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!--退款弹出框-->
|
||||||
|
<a-modal v-model:open="modalOpen" title="退款" destroyOnClose @ok="refund()">
|
||||||
|
<span>确定退款吗</span>
|
||||||
|
</a-modal>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {formatTime} from "../../../utils/TableConfig";
|
||||||
|
import router from "../../../router";
|
||||||
|
import myAxios from "../../../api/myAxios.ts";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
//订单信息
|
||||||
|
const tableData: any = ref([])
|
||||||
|
//店铺信息
|
||||||
|
const businessData: any = ref({})
|
||||||
|
//订单总金额
|
||||||
|
const ordersCount: any = ref<Number>()
|
||||||
|
//加载按钮
|
||||||
|
const loading = ref(false)
|
||||||
|
//弹出框开关
|
||||||
|
const modalOpen = ref<boolean>(false);
|
||||||
|
//退款id
|
||||||
|
const recordId = ref<Number>();
|
||||||
|
// 分页
|
||||||
|
const total: any = ref(0);
|
||||||
|
//查询条件
|
||||||
|
const searchParams: any = ref({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
orderId: null,
|
||||||
|
searchTime: null,
|
||||||
|
state: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{title: '订单号', dataIndex: 'id', key: 'id', width: 100, fixed: 'left', align: 'center'},
|
||||||
|
{
|
||||||
|
title: '下单时间', dataIndex: 'createTime', key: 'createTime', width: 100, align: 'center',
|
||||||
|
customRender: (row: any) => {
|
||||||
|
return formatTime(row)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '卖家昵称', dataIndex: 'userName', key: 'userName', width: 150, align: 'center'},
|
||||||
|
{title: '支付状态', dataIndex: 'state', key: 'state', width: 150, align: 'center'},
|
||||||
|
{title: '订单金额', dataIndex: 'totalPrice', key: 'totalPrice', width: 150, align: 'center'},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 80, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getOrdersList(1)
|
||||||
|
getBusinessVO()
|
||||||
|
getOrdersCount()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取订单信息列表
|
||||||
|
*/
|
||||||
|
const getOrdersList = async (current: any) => {
|
||||||
|
let businessId = route.query.id; //商家id
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post('/orders/list/page', {
|
||||||
|
businessId: businessId,
|
||||||
|
errandId: "",
|
||||||
|
current: current,
|
||||||
|
pageSize: searchParams.value.pageSize,
|
||||||
|
id: searchParams.value.orderId,
|
||||||
|
sortField: "createTime",
|
||||||
|
sortOrder: "descend",
|
||||||
|
state: searchParams.value.state,
|
||||||
|
startTime: searchParams.value.searchTime == null ? '' : searchParams.value.searchTime[0],
|
||||||
|
endTime: searchParams.value.searchTime == null ? '' : searchParams.value.searchTime[1]
|
||||||
|
})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
searchParams.value.current = current
|
||||||
|
tableData.value = res.data.records;
|
||||||
|
total.value = parseInt(res.data.total);
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取店铺信息
|
||||||
|
*/
|
||||||
|
const getBusinessVO = async () => {
|
||||||
|
let businessId = route.query.id; //商家id
|
||||||
|
const res: any = await myAxios.get('/business/getById', {params: {"id": businessId}})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
console.log(res)
|
||||||
|
businessData.value = res.data;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
console.log(res)
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取该店铺收入
|
||||||
|
*/
|
||||||
|
const getOrdersCount = async () => {
|
||||||
|
let businessId = route.query.id; //商家id
|
||||||
|
const res: any = await myAxios.post('/orders/count', {
|
||||||
|
"businessId": businessId,
|
||||||
|
"type": "money",
|
||||||
|
"state": 5
|
||||||
|
})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
ordersCount.value = res.data;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出Excel表
|
||||||
|
*/
|
||||||
|
const download = async () => {
|
||||||
|
let businessId = route.query.id //商家id
|
||||||
|
const res: any = await myAxios.post('/orders/download', {
|
||||||
|
businessId: businessId,
|
||||||
|
startTime: searchParams.value.searchTime?.[0] || '',
|
||||||
|
endTime: searchParams.value.searchTime?.[1] || '',
|
||||||
|
current: searchParams.value.current,
|
||||||
|
pageSize: searchParams.value.pageSize,
|
||||||
|
sortField: "createTime",
|
||||||
|
sortOrder: "descend"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
responseType: "blob"
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
console.log(res)
|
||||||
|
downloadCallback(res, '商家订单信息表.xlsx')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退款
|
||||||
|
*/
|
||||||
|
// const refund = async () => {
|
||||||
|
// const res: any = await myAxios.get('/Alipay/test/refund', {orderNo: recordId.value})
|
||||||
|
// if (res.code === 0 && res.data) {
|
||||||
|
// message.success('退款成功');
|
||||||
|
// modalOpen.value = false
|
||||||
|
// await getOrdersList(1)
|
||||||
|
// await getOrdersCount()
|
||||||
|
// } else {
|
||||||
|
// message.error(`退款失败:${res.message}`);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
const refund = async () => {
|
||||||
|
const res: any = await myAxios.get(`/Alipay/test/refund?orderNo=${recordId.value}`);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
message.success('退款成功');
|
||||||
|
modalOpen.value = false;
|
||||||
|
await getOrdersList(1);
|
||||||
|
await getOrdersCount();
|
||||||
|
} else {
|
||||||
|
message.error(`退款失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 查询
|
||||||
|
*/
|
||||||
|
const onSearch = async (ordersId: number) => {
|
||||||
|
searchParams.value.orderId = ordersId
|
||||||
|
await getOrdersList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询时间
|
||||||
|
*/
|
||||||
|
const searchTime = async (dateTime: any) => {
|
||||||
|
searchParams.value.searchTime = dateTime
|
||||||
|
await getOrdersList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
const onShowSizeChange = (current: number, pageSize: number) => {
|
||||||
|
searchParams.value.pageSize = pageSize;
|
||||||
|
getOrdersList(current);
|
||||||
|
}
|
||||||
|
const onChange = (pageNumber: number) => {
|
||||||
|
searchParams.value.current = pageNumber;
|
||||||
|
getOrdersList(pageNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回
|
||||||
|
*/
|
||||||
|
const back = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
//生成下载文件
|
||||||
|
const downloadCallback = (res: any, fileName: any) => {
|
||||||
|
const blob = new Blob([res]);
|
||||||
|
if ("download" in document.createElement("a")) {
|
||||||
|
// 非IE下载
|
||||||
|
const elink = document.createElement("a");
|
||||||
|
elink.download = fileName;
|
||||||
|
elink.style.display = "none";
|
||||||
|
elink.href = URL.createObjectURL(blob);
|
||||||
|
document.body.appendChild(elink);
|
||||||
|
elink.click();
|
||||||
|
URL.revokeObjectURL(elink.href); // 释放URL 对象
|
||||||
|
document.body.removeChild(elink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
179
CampusExpressDelivery/src/view/shop/order/StoreList.vue
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<div class="search-box">
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-space warp>
|
||||||
|
<a-form-item
|
||||||
|
label="店铺名"
|
||||||
|
>
|
||||||
|
<a-input allow-clear @change="change" @pressEnter="getBusinessList(1)"
|
||||||
|
v-model:value="searchParams.businessName"
|
||||||
|
placeholder="请输入店铺名"/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="店铺地"
|
||||||
|
>
|
||||||
|
<a-input allow-clear @change="change" @pressEnter="getBusinessList(1)" v-model:value="searchParams.address"
|
||||||
|
placeholder="请输入店铺地"/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="状态">
|
||||||
|
<a-select
|
||||||
|
style="width: 200px;"
|
||||||
|
placeholder="默认查询全部商家"
|
||||||
|
allowClear
|
||||||
|
v-model:value="searchParams.state"
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
|
<a-select-option value=0>休业</a-select-option>
|
||||||
|
<a-select-option value=1>营业</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-button type="primary" @click="getBusinessList(1)">查询</a-button>
|
||||||
|
<a-button @click="reset">重置</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1000, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination=false
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'businessAvatar'">
|
||||||
|
<a-avatar :src="record.businessAvatar"/>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'state'">
|
||||||
|
<div v-if="record.state === 0">
|
||||||
|
<a-tag color="purple">休业中</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.state === 1">
|
||||||
|
<a-tag color="blue">营业中</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button size="small"
|
||||||
|
type="link"
|
||||||
|
style="color: rgba(255, 141, 26, 1);"
|
||||||
|
@click="router.push({path: '/orderList',query: {id: record.id}})">查看
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<!-- 分页部分 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="searchParams.current"
|
||||||
|
v-model:pageSize="searchParams.pageSize"
|
||||||
|
show-quick-jumper
|
||||||
|
show-size-changer
|
||||||
|
:show-total="(total: any) => `共 ${total} 家店铺`"
|
||||||
|
:total="total"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import myAxios from "../../../api/myAxios";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import router from "../../../router";
|
||||||
|
|
||||||
|
//表单数据
|
||||||
|
const tableData: any = ref([]);
|
||||||
|
//加载按钮
|
||||||
|
const loading = ref(false)
|
||||||
|
// 分页
|
||||||
|
const total: any = ref(0);
|
||||||
|
//查询条件
|
||||||
|
const searchParams: any = ref({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
businessName: '',
|
||||||
|
address: '',
|
||||||
|
state: null
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 60,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({index}: any) => {
|
||||||
|
return `${(searchParams.value.current - 1) * searchParams.value.pageSize + index + 1}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '图片', dataIndex: 'businessAvatar', key: 'businessAvatar', width: 30, align: 'center'},
|
||||||
|
{title: '店铺名', dataIndex: 'businessName', key: 'businessName', width: 50, align: 'center'},
|
||||||
|
{title: '店铺地', dataIndex: 'address', key: 'address', width: 150, align: 'center'},
|
||||||
|
{title: '状态', dataIndex: 'state', key: 'state', width: 150, align: 'center'},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 50, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getBusinessList(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商家信息列表
|
||||||
|
*/
|
||||||
|
const getBusinessList = async (current: number) => {
|
||||||
|
searchParams.value.current = current
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post('/business/list/page', {...searchParams.value})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
tableData.value = res.data.records;
|
||||||
|
total.value = parseInt(res.data.total);
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择用户身份
|
||||||
|
*/
|
||||||
|
const handleChange = (state: string) => {
|
||||||
|
searchParams.value.state = state;
|
||||||
|
getBusinessList(1)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置查询条件
|
||||||
|
*/
|
||||||
|
const reset = () => {
|
||||||
|
searchParams.value.businessName = ''
|
||||||
|
searchParams.value.address = ''
|
||||||
|
searchParams.value.state = null
|
||||||
|
getBusinessList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
const onChange = (pageNumber: number) => {
|
||||||
|
searchParams.value.current = pageNumber;
|
||||||
|
getBusinessList(pageNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除输入框的回调
|
||||||
|
*/
|
||||||
|
const change = (row: any) => {
|
||||||
|
if (row.type === 'click') getBusinessList(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
3
CampusExpressDelivery/src/view/system/BusinessInfo.vue
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<div>管理员根据商家发布的公告进行查看管理</div>
|
||||||
|
</template>
|
||||||
160
CampusExpressDelivery/src/view/system/Carousel/Carousel.vue
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<a-card :loading="loading">
|
||||||
|
<div style="display: flex;justify-content: right;margin-bottom: 1%">
|
||||||
|
<a-button type="primary" @click="showModal">增加</a-button>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex;flex-wrap: wrap;">
|
||||||
|
<div v-for="item in carouselData" style="margin: 1.8%">
|
||||||
|
<a-card>
|
||||||
|
<template #cover>
|
||||||
|
<a-image :src="item?.content" style="width: 200px;height: 100px"/>
|
||||||
|
</template>
|
||||||
|
<template #actions>
|
||||||
|
<a-button type="primary" danger @click="deleteCarousel(item.id)">删除</a-button>
|
||||||
|
</template>
|
||||||
|
</a-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
<div>
|
||||||
|
<a-modal v-model:open="modalOpen" :afterClose="onClose" keyboard title="新增轮播图" @ok="submit">
|
||||||
|
<a-upload
|
||||||
|
style="margin: 5%"
|
||||||
|
:max-count="1"
|
||||||
|
name="avatar"
|
||||||
|
:show-upload-list="false"
|
||||||
|
:customRequest="handleChange"
|
||||||
|
list-type="picture-card"
|
||||||
|
class="avatar-uploader"
|
||||||
|
>
|
||||||
|
<img v-if="imageUrl" :src="imageUrl" alt="example" style="width: 100%"/>
|
||||||
|
<div v-else>
|
||||||
|
<div class="ant-upload-text">+</div>
|
||||||
|
</div>
|
||||||
|
</a-upload>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import myAxios from "../../../api/myAxios.ts";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
|
||||||
|
//加载按钮
|
||||||
|
const loading = ref(false)
|
||||||
|
//轮播图信息
|
||||||
|
const carouselData: any = ref({})
|
||||||
|
//弹出框开关
|
||||||
|
const modalOpen = ref<boolean>(false);
|
||||||
|
//图片地址
|
||||||
|
const imageUrl = ref('')
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getCarousel()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮播图列表
|
||||||
|
*/
|
||||||
|
const getCarousel = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post('/system/list', {
|
||||||
|
type: 1
|
||||||
|
})
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
loading.value = false;
|
||||||
|
carouselData.value = res.data
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除轮播图
|
||||||
|
*/
|
||||||
|
const deleteCarousel = async (id: number) => {
|
||||||
|
const res: any = await myAxios.post('/system/delete', {
|
||||||
|
id: id
|
||||||
|
})
|
||||||
|
if (res.code !== 0) {
|
||||||
|
message.error(`删除失败:${res.message}`);
|
||||||
|
}
|
||||||
|
await getCarousel()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开弹出框
|
||||||
|
*/
|
||||||
|
const showModal = () => {
|
||||||
|
if (carouselData.value.length > 7) {
|
||||||
|
message.error(`添加失败,轮播图不能大于8张`);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
modalOpen.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭弹出框
|
||||||
|
*/
|
||||||
|
const onClose = () => {
|
||||||
|
imageUrl.value = ""
|
||||||
|
modalOpen.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传图片
|
||||||
|
*/
|
||||||
|
const handleChange = async (row: any) => {
|
||||||
|
let formData = new FormData()
|
||||||
|
formData.append("file", row.file)
|
||||||
|
const result = await myAxios({
|
||||||
|
url: '/file/upload/server',
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
//biz: "user_avatar",
|
||||||
|
biz: "system",
|
||||||
|
// 需根据名字取出,否则为空
|
||||||
|
file: formData.get("file")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 传出图片地址
|
||||||
|
if (result.data) {
|
||||||
|
imageUrl.value = result.data
|
||||||
|
} else {
|
||||||
|
message.error(`图片上传失败`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认添加
|
||||||
|
*/
|
||||||
|
const submit = async () => {
|
||||||
|
if (imageUrl.value === '' || undefined) {
|
||||||
|
message.error(`请上传图片`);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const res: any = await myAxios.post('/system/add', {
|
||||||
|
type: 1,
|
||||||
|
content: imageUrl.value
|
||||||
|
})
|
||||||
|
if (res.code !== 0) {
|
||||||
|
message.error(`更新失败:${res.message}`);
|
||||||
|
}
|
||||||
|
await getCarousel()
|
||||||
|
modalOpen.value = false;
|
||||||
|
imageUrl.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
193
CampusExpressDelivery/src/view/system/Category.vue
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<div class="middle-button">
|
||||||
|
<a-button type="primary" @click="showDrawer">添加</a-button>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1500, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:rowKey="(record: any) => record.id"
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'image'">
|
||||||
|
<a-avatar :src="record.image"/>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button size="small" type="link" danger @click="handleDelete(record.id)">删除</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<a-drawer
|
||||||
|
:destroyOnClose="true"
|
||||||
|
title="添加分类"
|
||||||
|
placement="right"
|
||||||
|
:closable="false"
|
||||||
|
:visible="visible"
|
||||||
|
@close="onClose"
|
||||||
|
>
|
||||||
|
<a-form :model="drawerData" :rules="rules" layout="vertical">
|
||||||
|
<a-form-item name="content">
|
||||||
|
<a-input v-model:value="drawerData.name" placeholder="请输入分类名称"/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-upload
|
||||||
|
style="margin: 5%"
|
||||||
|
:max-count="1"
|
||||||
|
name="avatar"
|
||||||
|
:show-upload-list="false"
|
||||||
|
:customRequest="upload"
|
||||||
|
list-type="picture-card"
|
||||||
|
class="avatar-uploader"
|
||||||
|
>
|
||||||
|
<img v-if="drawerData.image" :src="drawerData.image" alt="example" style="width: 100%"/>
|
||||||
|
<div v-else>
|
||||||
|
<div class="ant-upload-text">+</div>
|
||||||
|
</div>
|
||||||
|
</a-upload>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<a-button style="margin-right: 8px" @click="onClose">取消</a-button>
|
||||||
|
<a-button type="primary" @click="onSubmit">确认</a-button>
|
||||||
|
</a-drawer>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {formatTime} from "../../utils/TableConfig";
|
||||||
|
import myAxios from "../../api/myAxios";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
|
||||||
|
const tableData: any = ref([]);
|
||||||
|
const loading = ref(false)
|
||||||
|
// 抽屉开关
|
||||||
|
const visible = ref<boolean>(false);
|
||||||
|
// 抽屉数据
|
||||||
|
const drawerData: any = ref({})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{title: '分类名', dataIndex: 'name', width: 30, align: 'center'},
|
||||||
|
{title: '分类图片', key: 'image', width: 30, align: 'center'},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
width: 30,
|
||||||
|
align: 'center',
|
||||||
|
customRender: (row: any) => {
|
||||||
|
return formatTime(row)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 30, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
name: [{required: true, message: '请输入分类名称'}],
|
||||||
|
image: [{required: true, message: '请输入分类图片'}],
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面加载时,请求数据
|
||||||
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
getCategoryList();
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取分类列表
|
||||||
|
*/
|
||||||
|
const getCategoryList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.get("/category/list");
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
tableData.value = res.data;
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传图片
|
||||||
|
*/
|
||||||
|
const upload = async (row: any) => {
|
||||||
|
let formData = new FormData()
|
||||||
|
formData.append("file", row.file)
|
||||||
|
const result = await myAxios({
|
||||||
|
url: '/file/upload/server',
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
biz: "system",
|
||||||
|
// 需根据名字取出,否则为空
|
||||||
|
file: formData.get("file")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 传出图片地址
|
||||||
|
if (result.data) {
|
||||||
|
drawerData.value.image = result.data
|
||||||
|
console.log(drawerData.value.image)
|
||||||
|
} else {
|
||||||
|
message.error(`图片上传失败`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抽屉
|
||||||
|
*/
|
||||||
|
const showDrawer = () => {
|
||||||
|
visible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭弹出框
|
||||||
|
*/
|
||||||
|
const onClose = () => {
|
||||||
|
drawerData.value = ref({})
|
||||||
|
visible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
const res: any = await myAxios.post('/category/add', {
|
||||||
|
name: drawerData.value.name,
|
||||||
|
image: drawerData.value.image
|
||||||
|
})
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 0) {
|
||||||
|
drawerData.value = ref('')
|
||||||
|
await getCategoryList()
|
||||||
|
message.success('添加分类成功')
|
||||||
|
} else {
|
||||||
|
message.error(`添加分类失败:${res.message}`);
|
||||||
|
}
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
const handleDelete = async (id: any) => {
|
||||||
|
const res: any = await myAxios.post("/category/delete", {id: id});
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
await getCategoryList();
|
||||||
|
message.success(`删除成功`);
|
||||||
|
} else {
|
||||||
|
message.error(`删除分类失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
145
CampusExpressDelivery/src/view/system/Info.vue
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<div class="middle-button">
|
||||||
|
<a-button type="primary" @click="showDrawer">添加</a-button>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1500, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:rowKey="(record: any) => record.id"
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button size="small" type="link" danger @click="handleDelete(record.id)">删除</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<a-drawer
|
||||||
|
:destroyOnClose="true"
|
||||||
|
title="添加公告"
|
||||||
|
placement="right"
|
||||||
|
:closable="false"
|
||||||
|
:visible="visible"
|
||||||
|
@close="visible=false;drawerData = {}"
|
||||||
|
>
|
||||||
|
<a-form :model="drawerData" :rules="rules" layout="vertical">
|
||||||
|
<a-form-item name="content">
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="drawerData.content"
|
||||||
|
placeholder="请输入公告信息"
|
||||||
|
:auto-size="{ minRows: 2, maxRows: 5 }"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<a-button style="margin-right: 8px" @click="onClose">取消</a-button>
|
||||||
|
<a-button type="primary" @click="onSubmit">确认</a-button>
|
||||||
|
</a-drawer>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import {formatTime} from "../../utils/TableConfig";
|
||||||
|
import myAxios from "../../api/myAxios";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
|
||||||
|
const tableData: any = ref([]);
|
||||||
|
const loading = ref(false)
|
||||||
|
// 抽屉开关
|
||||||
|
const visible = ref<boolean>(false);
|
||||||
|
// 抽屉数据
|
||||||
|
const drawerData: any = ref({})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{title: '公告内容', dataIndex: 'content', width: 100, align: 'center'},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
width: 50,
|
||||||
|
align: 'center',
|
||||||
|
customRender: (row: any) => {
|
||||||
|
return formatTime(row)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 30, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
content: [{required: true, message: '请输入公告信息'}],
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面加载时,请求数据
|
||||||
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
getInfoList();
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公告列表
|
||||||
|
*/
|
||||||
|
const getInfoList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post("/system/list", {type: 0});
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
tableData.value = res.data;
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抽屉
|
||||||
|
*/
|
||||||
|
const showDrawer = () => {
|
||||||
|
visible.value = true;
|
||||||
|
};
|
||||||
|
const onClose = () => {
|
||||||
|
drawerData.value = {}
|
||||||
|
visible.value = false;
|
||||||
|
};
|
||||||
|
const onSubmit = async () => {
|
||||||
|
if (drawerData.value.content?.indexOf(' ') !== -1 || drawerData.value.content == '') {
|
||||||
|
message.error(`格式错误,不允许存在空格`);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const res: any = await myAxios.post('/system/add', {
|
||||||
|
type: 0,
|
||||||
|
content: drawerData.value.content
|
||||||
|
})
|
||||||
|
if (res.code === 0) {
|
||||||
|
drawerData.value = {}
|
||||||
|
await getInfoList()
|
||||||
|
message.success('添加公告成功')
|
||||||
|
} else {
|
||||||
|
message.error(`添加公告失败:${res.message}`);
|
||||||
|
}
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
const handleDelete = async (id: any) => {
|
||||||
|
const res: any = await myAxios.post("/system/delete", {id: id});
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
await getInfoList();
|
||||||
|
message.success(`删除成功`);
|
||||||
|
} else {
|
||||||
|
message.error(`删除公告失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
222
CampusExpressDelivery/src/view/user/UserList.vue
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
<template>
|
||||||
|
<a-card>
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<div class="search-box">
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-space>
|
||||||
|
<a-form-item label="身份">
|
||||||
|
<a-select
|
||||||
|
style="width: 200px;"
|
||||||
|
placeholder="默认查询全部用户"
|
||||||
|
allowClear
|
||||||
|
v-model:value="searchParams.userRole"
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
|
<a-select-option value="user">普通用户</a-select-option>
|
||||||
|
<a-select-option value="business">商家用户</a-select-option>
|
||||||
|
<a-select-option value="errand">快送员</a-select-option>
|
||||||
|
<a-select-option value="admin">管理员</a-select-option>
|
||||||
|
<a-select-option value="ban">已封禁</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="用户昵称">
|
||||||
|
<a-input-search
|
||||||
|
style="width: 300px"
|
||||||
|
placeholder="请输入用户昵称"
|
||||||
|
enter-button
|
||||||
|
allow-clear
|
||||||
|
@search="onSearch"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="手机号">
|
||||||
|
<a-input-search
|
||||||
|
style="width: 300px"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
enter-button
|
||||||
|
allow-clear
|
||||||
|
@search="onSearchPhone"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
<!-- 数据展示部分 -->
|
||||||
|
<a-table
|
||||||
|
:scroll="{ x: 1500, y: 1000 }"
|
||||||
|
:data-source="tableData"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination=false
|
||||||
|
:loading="loading"
|
||||||
|
bordered
|
||||||
|
class="data-box"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'avatarUrl'">
|
||||||
|
<a-avatar :src="record.avatarUrl"/>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'userRole'">
|
||||||
|
<div v-if="record.userRole === 'boss'">
|
||||||
|
<a-tag color="purple">Boss</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.userRole === 'admin'">
|
||||||
|
<a-tag color="blue">管理员</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.userRole === 'user'">
|
||||||
|
<a-tag color="green">普通用户</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.userRole === 'errand'">
|
||||||
|
<a-tag color="yellow">快送员</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.userRole === 'business'">
|
||||||
|
<a-tag color="orange">商家</a-tag>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="record.userRole === 'ban'">
|
||||||
|
<a-tag color="red">已封禁</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === '操作'">
|
||||||
|
<a-space>
|
||||||
|
<a-button :disabled="validRole(record.userRole)"
|
||||||
|
size="small" type="link" danger @click="doBan(record.id, record.userRole === 'user')">
|
||||||
|
{{ record.userRole === 'ban' ? '解封' : '封禁' }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<!-- 分页部分 -->
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="searchParams.current"
|
||||||
|
v-model:pageSize="searchParams.pageSize"
|
||||||
|
show-quick-jumper
|
||||||
|
show-size-changer
|
||||||
|
:show-total="(total: any) => `共 ${total} 人`"
|
||||||
|
:total="total"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import myAxios from "../../api/myAxios.ts";
|
||||||
|
import {message} from "ant-design-vue";
|
||||||
|
import {formatTime} from "../../utils/TableConfig.ts";
|
||||||
|
|
||||||
|
|
||||||
|
const tableData: any = ref([]);
|
||||||
|
const loading = ref(false)
|
||||||
|
// 分页
|
||||||
|
const total: any = ref(0);
|
||||||
|
// 请求参数
|
||||||
|
const searchParams: any = ref({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
userRole: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: any = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
width: 40,
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({index}: any) => {
|
||||||
|
return `${(searchParams.value.current - 1) * searchParams.value.pageSize + index + 1}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '用户昵称', dataIndex: 'userAccount', width: 50, key: 'userAccount', fixed: 'left', align: 'center'},
|
||||||
|
{title: '头像', dataIndex: 'avatarUrl', key: 'avatarUrl', width: 30, align: 'center'},
|
||||||
|
{title: '身份', dataIndex: 'userRole', key: 'userRole', width: 50, align: 'center'},
|
||||||
|
{title: '手机号', dataIndex: 'phone', key: 'phone', width: 50, align: 'center'},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
width: 100,
|
||||||
|
align: 'center',
|
||||||
|
customRender: (row: any) => {
|
||||||
|
return formatTime(row)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{title: '操作', key: '操作', fixed: 'right', width: 30, align: 'center'},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面加载时,请求数据
|
||||||
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
getUserList();
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户数据
|
||||||
|
*/
|
||||||
|
const getUserList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res: any = await myAxios.post("/user/list/page", {...searchParams.value})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
console.log(res)
|
||||||
|
tableData.value = res.data.records;
|
||||||
|
total.value = parseInt(res.data.total);
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
message.error(`获取数据失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作
|
||||||
|
*/
|
||||||
|
const doBan = async (id: string, isBan: boolean) => {
|
||||||
|
const res: any = await myAxios.post("/user/update", {id: id, userRole: isBan ? 'ban' : 'user'})
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
message.success(`操作成功`);
|
||||||
|
await getUserList();
|
||||||
|
} else {
|
||||||
|
message.error(`封禁用户失败:${res.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择用户身份
|
||||||
|
*/
|
||||||
|
const handleChange = (userRole: string) => {
|
||||||
|
searchParams.value.userRole = userRole;
|
||||||
|
searchParams.value.current = 1;
|
||||||
|
getUserList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索功能
|
||||||
|
*/
|
||||||
|
const onSearch = (data: string) => {
|
||||||
|
searchParams.value.userAccount = data;
|
||||||
|
searchParams.value.current = 1;
|
||||||
|
getUserList();
|
||||||
|
}
|
||||||
|
const onSearchPhone = (data: string) => {
|
||||||
|
searchParams.value.phone = data;
|
||||||
|
searchParams.value.current = 1;
|
||||||
|
getUserList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
const onChange = (pageNumber: number) => {
|
||||||
|
searchParams.value.current = pageNumber;
|
||||||
|
getUserList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断用户权限
|
||||||
|
const validRole = (userRole: string) => {
|
||||||
|
return !(userRole === 'user' || userRole === 'ban');
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
10
CampusExpressDelivery/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
declare module '*.vue' {
|
||||||
|
import type {DefineComponent} from 'vue'
|
||||||
|
const vueComponent: DefineComponent<{}, {}, any>
|
||||||
|
export default vueComponent
|
||||||
|
}
|
||||||
|
declare module '*.mjs'
|
||||||
|
declare module 'dayjs'
|
||||||
|
|
||||||
|
|
||||||
26
CampusExpressDelivery/tsconfig.app.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||||
|
}
|
||||||
25
CampusExpressDelivery/tsconfig.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
||||||
11
CampusExpressDelivery/tsconfig.node.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
||||||
1
CampusExpressDelivery/tsconfig.node.tsbuildinfo
Normal file
1
CampusExpressDelivery/tsconfig.tsbuildinfo
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"root":["./src/main.ts","./src/vite-env.d.ts","./src/api/myaxios.ts","./src/router/index.ts","./src/router/routes.ts","./src/store/index.ts","./src/store/userstore.ts","./src/utils/tableconfig.ts","./src/app.vue","./src/layout/managelayout.vue","./src/layout/manage/manageheader.vue","./src/layout/manage/managesidebar.vue","./src/view/index.vue","./src/view/login.vue","./src/view/test.vue","./src/view/service/customerservice.vue","./src/view/echarts/brokenline.vue","./src/view/echarts/ordermethod.vue","./src/view/errand/errandinfo.vue","./src/view/errand/errandlist.vue","./src/view/errand/errandorderlist.vue","./src/view/errand/runlist.vue","./src/view/shop/businesslog.vue","./src/view/shop/business/businessinfo.vue","./src/view/shop/business/businessmanage.vue","./src/view/shop/business/dish.vue","./src/view/shop/business/dishgroup.vue","./src/view/shop/order/orderdetail.vue","./src/view/shop/order/orderlist.vue","./src/view/shop/order/storelist.vue","./src/view/system/businessinfo.vue","./src/view/system/category.vue","./src/view/system/info.vue","./src/view/system/carousel/carousel.vue","./src/view/user/userlist.vue"],"version":"5.6.3"}
|
||||||
2
CampusExpressDelivery/vite.config.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
declare const _default: import("vite").UserConfig;
|
||||||
|
export default _default;
|
||||||
40
CampusExpressDelivery/vite.config.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// import {defineConfig} from 'vite'
|
||||||
|
// import vue from '@vitejs/plugin-vue'
|
||||||
|
// import Components from 'unplugin-vue-components/vite';
|
||||||
|
// import {AntDesignVueResolver} from "unplugin-vue-components/resolvers";
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// export default defineConfig({
|
||||||
|
// plugins: [vue(),
|
||||||
|
// Components({
|
||||||
|
// resolvers: [
|
||||||
|
// AntDesignVueResolver({
|
||||||
|
// importStyle: false, // css in js
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
// }),],
|
||||||
|
// })
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
import Components from 'unplugin-vue-components/vite';
|
||||||
|
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
Components({
|
||||||
|
resolvers: [
|
||||||
|
AntDesignVueResolver({
|
||||||
|
importStyle: false, // css in js
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
// server: {
|
||||||
|
// https: true,
|
||||||
|
// https: {
|
||||||
|
// key: fs.readFileSync('/SSL/xiaokuaisong.shop.key'),
|
||||||
|
// cert: fs.readFileSync('/SSL/xiaokuaisong.shop.pem'),
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
});
|
||||||
41
CampusExpressDelivery/vite.config.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// import {defineConfig} from 'vite'
|
||||||
|
// import vue from '@vitejs/plugin-vue'
|
||||||
|
// import Components from 'unplugin-vue-components/vite';
|
||||||
|
// import {AntDesignVueResolver} from "unplugin-vue-components/resolvers";
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// export default defineConfig({
|
||||||
|
// plugins: [vue(),
|
||||||
|
// Components({
|
||||||
|
// resolvers: [
|
||||||
|
// AntDesignVueResolver({
|
||||||
|
// importStyle: false, // css in js
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
// }),],
|
||||||
|
// })
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import Components from 'unplugin-vue-components/vite'
|
||||||
|
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
Components({
|
||||||
|
resolvers: [
|
||||||
|
AntDesignVueResolver({
|
||||||
|
importStyle: false, // css in js
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
// server: {
|
||||||
|
// https: true,
|
||||||
|
// https: {
|
||||||
|
// key: fs.readFileSync('/SSL/xiaokuaisong.shop.key'),
|
||||||
|
// cert: fs.readFileSync('/SSL/xiaokuaisong.shop.pem'),
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
})
|
||||||