Compare commits
60 Commits
6cc2ba28a0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a71bef851 | |||
| 8ecc38befd | |||
| e205d1ddf4 | |||
| be05e4695c | |||
| 4b5f853603 | |||
| 6ff52e9d50 | |||
| 3535d33c4b | |||
| 0ec0bba2fa | |||
| 98f2842869 | |||
| f7e98f2a28 | |||
| b9f4936dcc | |||
| 3201a1c32b | |||
| 6aed1854ca | |||
| f8a605b8c0 | |||
| 08999c608d | |||
| 7eeac7c465 | |||
| 420f250bac | |||
| 3e59b58f84 | |||
| ac914f6c05 | |||
| 11887bf3d5 | |||
| 1fb76fc220 | |||
| d7d167f3e2 | |||
| 5b7dcd614a | |||
| 4dc541da85 | |||
| 223a59cd8a | |||
| 2fbae7f80f | |||
| 8940b3972a | |||
| 1b8bd5a7e2 | |||
| 45342fb55c | |||
| e5e1e5e2b3 | |||
| 94270b923c | |||
| aa7abbdde3 | |||
| 7b96e60b8d | |||
| 71639cad51 | |||
| d87732dbf7 | |||
| c0cfbbaa15 | |||
| f5e75b745f | |||
| 4d7946759c | |||
| 2bcc61fdaa | |||
| 63a1e126ad | |||
| f62613205c | |||
| 5ec0781a53 | |||
| e875a8e2d5 | |||
| 7032070d3f | |||
| ee20c19b72 | |||
| 5f3a7ca5b4 | |||
| ed0c8e6664 | |||
| 355a6c256d | |||
| 9e0b8ead79 | |||
| cc33d3028b | |||
| 930202a6b6 | |||
| 2e81e57774 | |||
| f60d78fe8b | |||
| f3c86b9775 | |||
| 38e25bf88a | |||
| ee9943f618 | |||
| d8e823f165 | |||
| b4e0d8ebc2 | |||
| b9c18375f5 | |||
| e5ff5608a8 |
1
.env.development
Normal file
1
.env.development
Normal file
@@ -0,0 +1 @@
|
||||
VITE_API_ALIST_PATH=/local/test
|
||||
1
.env.production
Normal file
1
.env.production
Normal file
@@ -0,0 +1 @@
|
||||
VITE_API_ALIST_PATH=/local
|
||||
@@ -1,6 +1,6 @@
|
||||
FROM docker-0.unsee.tech/nginx:1.27.0
|
||||
FROM nginx:1.27.0
|
||||
COPY dist/ /usr/share/nginx/html/
|
||||
COPY nginx.conf /etc/nginx/conf.d/
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
RUN echo 'Asia/Shanghai' > /etc/timezone
|
||||
RUN chmod -R 755 /usr/share/nginx/html/
|
||||
|
||||
114
components.d.ts
vendored
Normal file
114
components.d.ts
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// biome-ignore lint: disable
|
||||
// oxlint-disable
|
||||
// ------
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AnniversaryCard: typeof import('./src/components/Anniversary/AnniversaryCard.vue')['default']
|
||||
AnniversaryQuery: typeof import('./src/components/Anniversary/AnniversaryQuery.vue')['default']
|
||||
AppLoading: typeof import('./src/components/Common/AppLoading.vue')['default']
|
||||
ArriveButton: typeof import('./src/components/Common/ArriveButton.vue')['default']
|
||||
AssetCard: typeof import('./src/components/Asset/AssetCard.vue')['default']
|
||||
AssetQuery: typeof import('./src/components/Asset/AssetQuery.vue')['default']
|
||||
AwardCard: typeof import('./src/components/Award/AwardCard.vue')['default']
|
||||
AwardQuery: typeof import('./src/components/Award/AwardQuery.vue')['default']
|
||||
BillCalendar: typeof import('./src/components/Bill/BillCalendar.vue')['default']
|
||||
BillChart: typeof import('./src/components/Bill/BillChart.vue')['default']
|
||||
BillDailyItem: typeof import('./src/components/Bill/BillDailyItem.vue')['default']
|
||||
BillDailyList: typeof import('./src/components/Bill/BillDailyList.vue')['default']
|
||||
BillDrawer: typeof import('./src/components/Bill/BillDrawer.vue')['default']
|
||||
BillQuery: typeof import('./src/components/Bill/BillQuery.vue')['default']
|
||||
BillRank: typeof import('./src/components/Bill/BillRank.vue')['default']
|
||||
BillSearch: typeof import('./src/components/Bill/BillSearch.vue')['default']
|
||||
BillStats: typeof import('./src/components/Bill/BillStats.vue')['default']
|
||||
BlogArchive: typeof import('./src/components/Blog/Archive/BlogArchive.vue')['default']
|
||||
BlogCategory: typeof import('./src/components/Blog/Category/BlogCategory.vue')['default']
|
||||
BlogCategoryDetail: typeof import('./src/components/Blog/Category/BlogCategoryDetail.vue')['default']
|
||||
BlogComment: typeof import('./src/components/Blog/Comment/BlogComment.vue')['default']
|
||||
BlogDetail: typeof import('./src/components/Blog/Content/BlogDetail.vue')['default']
|
||||
BlogLabel: typeof import('./src/components/Blog/Content/BlogLabel.vue')['default']
|
||||
BlogOverview: typeof import('./src/components/Blog/Content/BlogOverview.vue')['default']
|
||||
CarCard: typeof import('./src/components/Car/CarCard.vue')['default']
|
||||
CarQuery: typeof import('./src/components/Car/CarQuery.vue')['default']
|
||||
CategoryCard: typeof import('./src/components/Anniversary/CategoryCard.vue')['default']
|
||||
CommonLogin: typeof import('./src/components/Login/CommonLogin.vue')['default']
|
||||
DailyCard: typeof import('./src/components/DailyCard.vue')['default']
|
||||
DailySummary: typeof import('./src/components/DailySummary.vue')['default']
|
||||
EmailLogin: typeof import('./src/components/Login/EmailLogin.vue')['default']
|
||||
FoodBasicData: typeof import('./src/components/Food/Data/FoodBasicData.vue')['default']
|
||||
FoodCalendar: typeof import('./src/components/Food/FoodCalendar.vue')['default']
|
||||
FoodCard: typeof import('./src/components/Food/FoodCard.vue')['default']
|
||||
FoodDailyItem: typeof import('./src/components/Food/FoodDailyItem.vue')['default']
|
||||
FoodMaterialData: typeof import('./src/components/Food/Data/FoodMaterialData.vue')['default']
|
||||
FoodMaterialDialog: typeof import('./src/components/Food/Form/FoodMaterialDialog.vue')['default']
|
||||
FoodMaterialForm: typeof import('./src/components/Food/Form/FoodMaterialForm.vue')['default']
|
||||
FoodOthersData: typeof import('./src/components/Food/Data/FoodOthersData.vue')['default']
|
||||
FoodQuery: typeof import('./src/components/Food/FoodQuery.vue')['default']
|
||||
FoodRecordData: typeof import('./src/components/Food/Data/FoodRecordData.vue')['default']
|
||||
FoodStats: typeof import('./src/components/Food/FoodStats.vue')['default']
|
||||
FoodStepData: typeof import('./src/components/Food/Data/FoodStepData.vue')['default']
|
||||
FoodStepDialog: typeof import('./src/components/Food/Form/FoodStepDialog.vue')['default']
|
||||
FoodStepForm: typeof import('./src/components/Food/Form/FoodStepForm.vue')['default']
|
||||
HealthChart: typeof import('./src/components/Health/HealthChart.vue')['default']
|
||||
HealthForm: typeof import('./src/components/Health/HealthForm.vue')['default']
|
||||
HealthStats: typeof import('./src/components/Health/HealthStats.vue')['default']
|
||||
HomeQuery: typeof import('./src/components/HomeQuery.vue')['default']
|
||||
JournalCalendar: typeof import('./src/components/Journal/JournalCalendar.vue')['default']
|
||||
JournalCard: typeof import('./src/components/Journal/JournalCard.vue')['default']
|
||||
JournalDrawer: typeof import('./src/components/Journal/JournalDrawer.vue')['default']
|
||||
KpiCalendar: typeof import('./src/components/kpi/KpiCalendar.vue')['default']
|
||||
KpiCard: typeof import('./src/components/kpi/KpiCard.vue')['default']
|
||||
LedgerCard: typeof import('./src/components/Ledger/LedgerCard.vue')['default']
|
||||
LedgerQuery: typeof import('./src/components/Ledger/LedgerQuery.vue')['default']
|
||||
LedgerRank: typeof import('./src/components/Ledger/LedgerRank.vue')['default']
|
||||
LoginAuth: typeof import('./src/components/Login/LoginAuth.vue')['default']
|
||||
Milestone: typeof import('./src/components/Milestone.vue')['default']
|
||||
MobileSetting: typeof import('./src/components/Common/MobileSetting.vue')['default']
|
||||
ModuleCard: typeof import('./src/components/ModuleCard.vue')['default']
|
||||
NumberInput: typeof import('./src/components/NumberInput.vue')['default']
|
||||
PasswordCard: typeof import('./src/components/Password/PasswordCard.vue')['default']
|
||||
PasswordQuery: typeof import('./src/components/Password/PasswordQuery.vue')['default']
|
||||
PeriodForm: typeof import('./src/components/Period/PeriodForm.vue')['default']
|
||||
PeriodLegend: typeof import('./src/components/Period/PeriodLegend.vue')['default']
|
||||
PhoneLogin: typeof import('./src/components/Login/PhoneLogin.vue')['default']
|
||||
PlanCalendar: typeof import('./src/components/Plan/PlanCalendar.vue')['default']
|
||||
PlanCard: typeof import('./src/components/Plan/PlanCard.vue')['default']
|
||||
PlanQuery: typeof import('./src/components/Plan/PlanQuery.vue')['default']
|
||||
ProductCard: typeof import('./src/components/Product/ProductCard.vue')['default']
|
||||
ProductDrawer: typeof import('./src/components/Product/ProductDrawer.vue')['default']
|
||||
ProductQuery: typeof import('./src/components/Product/ProductQuery.vue')['default']
|
||||
ProfileAccount: typeof import('./src/components/Profile/ProfileAccount.vue')['default']
|
||||
ProfileInfo: typeof import('./src/components/Profile/ProfileInfo.vue')['default']
|
||||
ProfilePassword: typeof import('./src/components/Profile/ProfilePassword.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
ServerCard: typeof import('./src/components/Server/ServerCard.vue')['default']
|
||||
ServerProgress: typeof import('./src/components/Server/ServerProgress.vue')['default']
|
||||
StatsCard: typeof import('./src/components/StatsCard.vue')['default']
|
||||
TravelBasicData: typeof import('./src/components/Travel/Data/TravelBasicData.vue')['default']
|
||||
TravelCalendar: typeof import('./src/components/Travel/TravelCalendar.vue')['default']
|
||||
TravelCard: typeof import('./src/components/Travel/TravelCard.vue')['default']
|
||||
TravelConsumeData: typeof import('./src/components/Travel/Data/TravelConsumeData.vue')['default']
|
||||
TravelDailyItem: typeof import('./src/components/Travel/TravelDailyItem.vue')['default']
|
||||
TravelDailyList: typeof import('./src/components/Travel/TravelDailyList.vue')['default']
|
||||
TravelDialog: typeof import('./src/components/Travel/TravelDialog.vue')['default']
|
||||
TravelGuideData: typeof import('./src/components/Travel/Data/TravelGuideData.vue')['default']
|
||||
TravelQuery: typeof import('./src/components/Travel/TravelQuery.vue')['default']
|
||||
TravelRecordData: typeof import('./src/components/Travel/Data/TravelRecordData.vue')['default']
|
||||
TravelSpotList: typeof import('./src/components/Travel/TravelSpotList.vue')['default']
|
||||
TravelStats: typeof import('./src/components/Travel/TravelStats.vue')['default']
|
||||
VanButton: typeof import('vant/es')['Button']
|
||||
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
||||
VanFloatingBubble: typeof import('vant/es')['FloatingBubble']
|
||||
VanSwipeCell: typeof import('vant/es')['SwipeCell']
|
||||
WeatherIcon: typeof import('./src/components/Common/WeatherIcon.vue')['default']
|
||||
WeatherTimeCard: typeof import('./src/components/Common/WeatherTimeCard.vue')['default']
|
||||
}
|
||||
}
|
||||
107
nginx.conf
107
nginx.conf
@@ -1,106 +1,41 @@
|
||||
##
|
||||
# You should look at the following URL's in order to grasp a solid understanding
|
||||
# of Nginx configuration files in order to fully unleash the power of Nginx.
|
||||
# https://www.nginx.com/resources/wiki/start/
|
||||
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
|
||||
# https://wiki.debian.org/Nginx/DirectoryStructure
|
||||
#
|
||||
# In most cases, administrators will remove this file from sites-enabled/ and
|
||||
# leave it as reference inside of sites-available where it will continue to be
|
||||
# updated by the nginx packaging team.
|
||||
#
|
||||
# This file will automatically load configuration files provided by other
|
||||
# applications, such as Drupal or Wordpress. These applications will be made
|
||||
# available underneath a path with that package name, such as /drupal8.
|
||||
#
|
||||
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
|
||||
##
|
||||
|
||||
# Default server configuration
|
||||
#
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
# SSL configuration
|
||||
#
|
||||
# listen 443 ssl default_server;
|
||||
# listen [::]:443 ssl default_server;
|
||||
#
|
||||
# Note: You should disable gzip for SSL traffic.
|
||||
# See: https://bugs.debian.org/773332
|
||||
#
|
||||
# Read up on ssl_ciphers to ensure a secure configuration.
|
||||
# See: https://bugs.debian.org/765782
|
||||
#
|
||||
# Self signed certs generated by the ssl-cert package
|
||||
# Don't use them in a production server!
|
||||
#
|
||||
# include snippets/snakeoil.conf;
|
||||
|
||||
#root /var/www/html;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
# Add index.php to the list if you are using PHP
|
||||
#index index.html index.htm index.nginx-debian.html;
|
||||
index index.html;
|
||||
|
||||
server_name _;
|
||||
|
||||
location /admin-service/ {
|
||||
proxy_pass http://admin-service:8080/;
|
||||
client_max_body_size 500M;
|
||||
|
||||
location /sweet-hut/ {
|
||||
alias /usr/share/nginx/html/;
|
||||
try_files $uri $uri/ /sweet-hut/index.html;
|
||||
}
|
||||
|
||||
location /home-service/ {
|
||||
proxy_pass http://home-service:8081/;
|
||||
location /home-api/ {
|
||||
proxy_pass http://host.docker.internal:8081/;
|
||||
}
|
||||
|
||||
location /blog-service/ {
|
||||
proxy_pass http://blog-service:8082/;
|
||||
location /alist-api/ {
|
||||
proxy_pass http://host.docker.internal:5244/;
|
||||
}
|
||||
|
||||
location /blog-api/ {
|
||||
proxy_pass http://host.docker.internal:8082/;
|
||||
}
|
||||
|
||||
location /image-api/ {
|
||||
proxy_pass http://host.docker.internal:3000/;
|
||||
}
|
||||
|
||||
location /agent-api/ {
|
||||
proxy_pass http://host.docker.internal:8000/;
|
||||
}
|
||||
|
||||
location / {
|
||||
# First attempt to serve request as file, then
|
||||
# as directory, then fall back to displaying a 404.
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# pass PHP scripts to FastCGI server
|
||||
#
|
||||
#location ~ \.php$ {
|
||||
# include snippets/fastcgi-php.conf;
|
||||
#
|
||||
# # With php-fpm (or other unix sockets):
|
||||
# fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
|
||||
# # With php-cgi (or other tcp sockets):
|
||||
# fastcgi_pass 127.0.0.1:9000;
|
||||
#}
|
||||
|
||||
# deny access to .htaccess files, if Apache's document root
|
||||
# concurs with nginx's one
|
||||
#
|
||||
#location ~ /\.ht {
|
||||
# deny all;
|
||||
#}
|
||||
}
|
||||
|
||||
|
||||
# Virtual Host configuration for example.com
|
||||
#
|
||||
# You can move that to a different file under sites-available/ and symlink that
|
||||
# to sites-enabled/ to enable it.
|
||||
#
|
||||
#server {
|
||||
# listen 80;
|
||||
# listen [::]:80;
|
||||
#
|
||||
# server_name example.com;
|
||||
#
|
||||
# root /var/www/example.com;
|
||||
# index index.html;
|
||||
#
|
||||
# location / {
|
||||
# try_files $uri $uri/ =404;
|
||||
# }
|
||||
#}
|
||||
|
||||
|
||||
177
package-lock.json
generated
177
package-lock.json
generated
@@ -29,9 +29,11 @@
|
||||
"lunar-javascript": "^1.7.2",
|
||||
"md-editor-v3": "^4.21.3",
|
||||
"pinia": "^2.3.1",
|
||||
"ua-parser-js": "^2.0.3",
|
||||
"v-calendar": "^3.1.2",
|
||||
"vue": "3.5.12",
|
||||
"vue3-common": "git+https://gitee.com/Cxx0822/vue3-common",
|
||||
"vue3-emoji-picker": "^1.1.8",
|
||||
"vue3-eslint": "git+https://gitee.com/Cxx0822/vue3-eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -2737,12 +2739,21 @@
|
||||
"version": "18.19.86",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.19.86.tgz",
|
||||
"integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/resize-observer-browser": {
|
||||
"version": "0.1.11",
|
||||
"resolved": "https://registry.npmmirror.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.11.tgz",
|
||||
@@ -3519,8 +3530,7 @@
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/atob": {
|
||||
"version": "2.1.2",
|
||||
@@ -4019,7 +4029,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
@@ -4488,11 +4497,30 @@
|
||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-europe-js": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/detect-europe-js/-/detect-europe-js-0.1.2.tgz",
|
||||
"integrity": "sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/faisalman"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ua-parser-js"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/faisalman"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
@@ -5848,7 +5876,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.2.tgz",
|
||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -6372,6 +6399,12 @@
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/idb": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/idb/-/idb-7.1.1.tgz",
|
||||
"integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz",
|
||||
@@ -6844,6 +6877,26 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-standalone-pwa": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-standalone-pwa/-/is-standalone-pwa-0.1.1.tgz",
|
||||
"integrity": "sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/faisalman"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ua-parser-js"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/faisalman"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-string": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.1.1.tgz",
|
||||
@@ -7400,7 +7453,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -7410,7 +7462,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
@@ -7636,6 +7687,26 @@
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.19",
|
||||
"resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz",
|
||||
@@ -10207,6 +10278,12 @@
|
||||
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/traverse": {
|
||||
"version": "0.6.11",
|
||||
"resolved": "https://registry.npmmirror.com/traverse/-/traverse-0.6.11.tgz",
|
||||
@@ -10406,6 +10483,59 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/ua-is-frozen": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/ua-is-frozen/-/ua-is-frozen-0.1.2.tgz",
|
||||
"integrity": "sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/faisalman"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ua-parser-js"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/faisalman"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ua-parser-js": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/ua-parser-js/-/ua-parser-js-2.0.3.tgz",
|
||||
"integrity": "sha512-LZyXZdNttONW8LjzEH3Z8+6TE7RfrEiJqDKyh0R11p/kxvrV2o9DrT2FGZO+KVNs3k+drcIQ6C3En6wLnzJGpw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ua-parser-js"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/faisalman"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/faisalman"
|
||||
}
|
||||
],
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@types/node-fetch": "^2.6.12",
|
||||
"detect-europe-js": "^0.1.2",
|
||||
"is-standalone-pwa": "^0.1.1",
|
||||
"node-fetch": "^2.7.0",
|
||||
"ua-is-frozen": "^0.1.2"
|
||||
},
|
||||
"bin": {
|
||||
"ua-parser-js": "script/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
@@ -10434,7 +10564,6 @@
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/union-value": {
|
||||
@@ -11406,6 +11535,20 @@
|
||||
"vue-router": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/vue3-emoji-picker": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmmirror.com/vue3-emoji-picker/-/vue3-emoji-picker-1.1.8.tgz",
|
||||
"integrity": "sha512-k9tVHeQEBVLzVCLYAkFaI1nib3FJFQwdPhWD5khJkhks3ktg3g12z5wPGOSDpIuSLNtelRGvq1qdmZuJu5khfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.0",
|
||||
"idb": "^7.1.0",
|
||||
"vue": "^3.2.23"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue3-eslint": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "git+https://gitee.com/Cxx0822/vue3-eslint#849a4e0e783d3ecc57035fb2f92950998b6b2e41",
|
||||
@@ -11444,6 +11587,22 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url/node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
|
||||
|
||||
20
package.json
20
package.json
@@ -2,6 +2,7 @@
|
||||
"name": "sweet-hut-ui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host 0.0.0.0",
|
||||
"build": "vite build",
|
||||
@@ -23,35 +24,32 @@
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts-liquidfill": "^3.1.0",
|
||||
"element-china-area-data": "^6.1.0",
|
||||
"element-plus": "~2.9.7",
|
||||
"element-plus": "^2.9.7",
|
||||
"file-icons-vue": "^1.3.4",
|
||||
"font-awesome": "^4.7.0",
|
||||
"lunar-javascript": "^1.7.2",
|
||||
"md-editor-v3": "^4.21.3",
|
||||
"pinia": "^2.3.1",
|
||||
"ua-parser-js": "^2.0.3",
|
||||
"v-calendar": "^3.1.2",
|
||||
"vant": "^4.9.22",
|
||||
"vue": "3.5.12",
|
||||
"vue3-common": "git+https://gitee.com/Cxx0822/vue3-common",
|
||||
"vue3-emoji-picker": "^1.1.8",
|
||||
"vue3-eslint": "git+https://gitee.com/Cxx0822/vue3-eslint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.19.86",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"@vitejs/plugin-vue": "5.2.1",
|
||||
"@vant/auto-import-resolver": "^1.3.0",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.2.0",
|
||||
"eslint-plugin-vue": "^8.7.1",
|
||||
"postcss": "^8.5.3",
|
||||
"sass": "^1.86.3",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.8.3",
|
||||
"unplugin-vue-components": "^32.1.0",
|
||||
"vfonts": "^0.0.3",
|
||||
"vite": "5.2.0",
|
||||
"vite": "^5.2.0",
|
||||
"vite-plugin-mock": "^3.0.2",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue-tsc": "^1.8.27"
|
||||
|
||||
370
pnpm-lock.yaml
generated
370
pnpm-lock.yaml
generated
@@ -54,7 +54,7 @@ importers:
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0
|
||||
element-plus:
|
||||
specifier: ~2.9.7
|
||||
specifier: ^2.9.7
|
||||
version: 2.9.7(vue@3.5.12(typescript@5.8.3))
|
||||
file-icons-vue:
|
||||
specifier: ^1.3.4
|
||||
@@ -71,15 +71,24 @@ importers:
|
||||
pinia:
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1(typescript@5.8.3)(vue@3.5.12(typescript@5.8.3))
|
||||
ua-parser-js:
|
||||
specifier: ^2.0.3
|
||||
version: 2.0.6
|
||||
v-calendar:
|
||||
specifier: ^3.1.2
|
||||
version: 3.1.2(@popperjs/core@2.11.8)(vue@3.5.12(typescript@5.8.3))
|
||||
vant:
|
||||
specifier: ^4.9.22
|
||||
version: 4.9.22(vue@3.5.12(typescript@5.8.3))
|
||||
vue:
|
||||
specifier: 3.5.12
|
||||
version: 3.5.12(typescript@5.8.3)
|
||||
vue3-common:
|
||||
specifier: git+https://gitee.com/Cxx0822/vue3-common
|
||||
version: git+https://gitee.com/Cxx0822/vue3-common#ba7c8a0b1a20a714f0bf09b10d9486b5fd518ca0(axios@1.9.0)(crypto-js@4.2.0)(echarts@5.6.0)(element-plus@2.9.7(vue@3.5.12(typescript@5.8.3)))(font-awesome@4.7.0)(js-cookie@3.0.5)(path-browserify@1.0.1)(pinia@2.3.1(typescript@5.8.3)(vue@3.5.12(typescript@5.8.3)))(qs@6.14.0)(vue-router@4.5.1(vue@3.5.12(typescript@5.8.3)))(vue@3.5.12(typescript@5.8.3))
|
||||
vue3-emoji-picker:
|
||||
specifier: ^1.1.8
|
||||
version: 1.1.8(typescript@5.8.3)
|
||||
vue3-eslint:
|
||||
specifier: git+https://gitee.com/Cxx0822/vue3-eslint
|
||||
version: git+https://gitee.com/Cxx0822/vue3-eslint#849a4e0e783d3ecc57035fb2f92950998b6b2e41(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)(typescript@5.8.3))(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint-config-standard@16.0.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0))(eslint-plugin-node@11.1.0(eslint@7.32.0))(eslint-plugin-promise@5.2.0(eslint@7.32.0))(eslint@7.32.0))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0))(eslint-plugin-node@11.1.0(eslint@7.32.0))(eslint-plugin-promise@5.2.0(eslint@7.32.0))(eslint-plugin-vue@8.7.1(eslint@7.32.0))(eslint@7.32.0)
|
||||
@@ -87,36 +96,15 @@ importers:
|
||||
'@types/node':
|
||||
specifier: ^18.19.86
|
||||
version: 18.19.86
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^5.62.0
|
||||
version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)(typescript@5.8.3)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^5.62.0
|
||||
version: 5.62.0(eslint@7.32.0)(typescript@5.8.3)
|
||||
'@vant/auto-import-resolver':
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: 5.2.1
|
||||
specifier: ^5.2.1
|
||||
version: 5.2.1(vite@5.2.0(@types/node@18.19.86)(sass@1.86.3))(vue@3.5.12(typescript@5.8.3))
|
||||
autoprefixer:
|
||||
specifier: ^10.4.21
|
||||
version: 10.4.21(postcss@8.5.3)
|
||||
eslint:
|
||||
specifier: ^7.32.0
|
||||
version: 7.32.0
|
||||
eslint-config-standard:
|
||||
specifier: ^16.0.3
|
||||
version: 16.0.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0))(eslint-plugin-node@11.1.0(eslint@7.32.0))(eslint-plugin-promise@5.2.0(eslint@7.32.0))(eslint@7.32.0)
|
||||
eslint-plugin-import:
|
||||
specifier: ^2.31.0
|
||||
version: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)
|
||||
eslint-plugin-node:
|
||||
specifier: ^11.1.0
|
||||
version: 11.1.0(eslint@7.32.0)
|
||||
eslint-plugin-promise:
|
||||
specifier: ^5.2.0
|
||||
version: 5.2.0(eslint@7.32.0)
|
||||
eslint-plugin-vue:
|
||||
specifier: ^8.7.1
|
||||
version: 8.7.1(eslint@7.32.0)
|
||||
postcss:
|
||||
specifier: ^8.5.3
|
||||
version: 8.5.3
|
||||
@@ -129,11 +117,14 @@ importers:
|
||||
typescript:
|
||||
specifier: ^5.8.3
|
||||
version: 5.8.3
|
||||
unplugin-vue-components:
|
||||
specifier: ^32.1.0
|
||||
version: 32.1.0(esbuild@0.20.2)(rollup@4.40.0)(vite@5.2.0(@types/node@18.19.86)(sass@1.86.3))(vue@3.5.12(typescript@5.8.3))
|
||||
vfonts:
|
||||
specifier: ^0.0.3
|
||||
version: 0.0.3
|
||||
vite:
|
||||
specifier: 5.2.0
|
||||
specifier: ^5.2.0
|
||||
version: 5.2.0(@types/node@18.19.86)(sass@1.86.3)
|
||||
vite-plugin-mock:
|
||||
specifier: ^3.0.2
|
||||
@@ -486,6 +477,9 @@ packages:
|
||||
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
'@jridgewell/remapping@2.3.5':
|
||||
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
|
||||
|
||||
'@jridgewell/resolve-uri@3.1.2':
|
||||
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@@ -497,6 +491,9 @@ packages:
|
||||
'@jridgewell/sourcemap-codec@1.5.0':
|
||||
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5':
|
||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||
|
||||
@@ -993,6 +990,17 @@ packages:
|
||||
resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
||||
'@vant/auto-import-resolver@1.3.0':
|
||||
resolution: {integrity: sha512-lJyWtCyFizR4bHZvMiNMF3w+WTFTUWAvka1eqTnPK9ticUcKTCOx6qEmHcm8JPb3g1t3GaD2W3MnHkBp/nHamw==}
|
||||
|
||||
'@vant/popperjs@1.3.0':
|
||||
resolution: {integrity: sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==}
|
||||
|
||||
'@vant/use@1.6.0':
|
||||
resolution: {integrity: sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
'@vavt/util@2.1.0':
|
||||
resolution: {integrity: sha512-YIfAvArSFVXmWvoF+DEGD0FhkhVNcCtVWWkfYtj76eSrwHh/wuEEFhiEubg1XLNM3tChO8FH8xJCT/hnizjgFQ==}
|
||||
|
||||
@@ -1061,6 +1069,9 @@ packages:
|
||||
'@vue/shared@3.5.13':
|
||||
resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==}
|
||||
|
||||
'@vue/shared@3.5.28':
|
||||
resolution: {integrity: sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==}
|
||||
|
||||
'@vueuse/core@13.1.0':
|
||||
resolution: {integrity: sha512-PAauvdRXZvTWXtGLg8cPUFjiZEddTqmogdwYpnn60t08AA5a8Q4hZokBnpTOnVNqySlFlTcRYIC8OqreV4hv3Q==}
|
||||
peerDependencies:
|
||||
@@ -1093,8 +1104,13 @@ packages:
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
acorn@8.14.1:
|
||||
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
|
||||
acorn@8.15.0:
|
||||
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
acorn@8.18.0:
|
||||
resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1334,6 +1350,10 @@ packages:
|
||||
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
||||
engines: {node: '>= 14.16.0'}
|
||||
|
||||
chokidar@5.0.0:
|
||||
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
|
||||
engines: {node: '>= 20.19.0'}
|
||||
|
||||
class-utils@0.3.6:
|
||||
resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1393,6 +1413,12 @@ packages:
|
||||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
confbox@0.1.8:
|
||||
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
|
||||
|
||||
confbox@0.2.4:
|
||||
resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==}
|
||||
|
||||
connect@3.7.0:
|
||||
resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==}
|
||||
engines: {node: '>= 0.10.0'}
|
||||
@@ -1527,6 +1553,9 @@ packages:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
detect-europe-js@0.1.2:
|
||||
resolution: {integrity: sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==}
|
||||
|
||||
detect-libc@1.0.3:
|
||||
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
|
||||
engines: {node: '>=0.10'}
|
||||
@@ -1826,6 +1855,9 @@ packages:
|
||||
resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
exsolve@1.1.1:
|
||||
resolution: {integrity: sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==}
|
||||
|
||||
extend-shallow@2.0.1:
|
||||
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1857,6 +1889,15 @@ packages:
|
||||
fastq@1.19.1:
|
||||
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
|
||||
|
||||
fdir@6.5.0:
|
||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
peerDependencies:
|
||||
picomatch: ^3 || ^4
|
||||
peerDependenciesMeta:
|
||||
picomatch:
|
||||
optional: true
|
||||
|
||||
file-entry-cache@6.0.1:
|
||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||
engines: {node: ^10.12.0 || >=12.0.0}
|
||||
@@ -2064,6 +2105,9 @@ packages:
|
||||
htmlparser2@3.10.1:
|
||||
resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
|
||||
|
||||
idb@7.1.1:
|
||||
resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==}
|
||||
|
||||
ignore@4.0.6:
|
||||
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
|
||||
engines: {node: '>= 4'}
|
||||
@@ -2222,6 +2266,9 @@ packages:
|
||||
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-standalone-pwa@0.1.1:
|
||||
resolution: {integrity: sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==}
|
||||
|
||||
is-string@1.1.1:
|
||||
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2348,6 +2395,10 @@ packages:
|
||||
resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
|
||||
local-pkg@1.2.1:
|
||||
resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
lodash-es@4.17.21:
|
||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
|
||||
@@ -2379,6 +2430,9 @@ packages:
|
||||
magic-string@0.30.17:
|
||||
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
||||
|
||||
magic-string@0.30.21:
|
||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||
|
||||
map-cache@0.2.2:
|
||||
resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2466,6 +2520,9 @@ packages:
|
||||
resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
mlly@1.8.2:
|
||||
resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==}
|
||||
|
||||
mockjs@1.1.0:
|
||||
resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==}
|
||||
hasBin: true
|
||||
@@ -2561,6 +2618,10 @@ packages:
|
||||
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
obug@2.1.4:
|
||||
resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
|
||||
on-finished@2.3.0:
|
||||
resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -2619,6 +2680,9 @@ packages:
|
||||
pathe@0.2.0:
|
||||
resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==}
|
||||
|
||||
pathe@2.0.3:
|
||||
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
@@ -2626,6 +2690,10 @@ packages:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
picomatch@4.0.5:
|
||||
resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
pify@2.3.0:
|
||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2643,6 +2711,12 @@ packages:
|
||||
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
pkg-types@1.3.1:
|
||||
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
||||
|
||||
pkg-types@2.3.1:
|
||||
resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==}
|
||||
|
||||
posix-character-classes@0.1.1:
|
||||
resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2744,6 +2818,9 @@ packages:
|
||||
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
quansync@0.2.11:
|
||||
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
|
||||
|
||||
query-string@4.3.4:
|
||||
resolution: {integrity: sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2766,6 +2843,10 @@ packages:
|
||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||
engines: {node: '>= 14.18.0'}
|
||||
|
||||
readdirp@5.0.0:
|
||||
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
|
||||
engines: {node: '>= 20.19.0'}
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -3068,6 +3149,10 @@ packages:
|
||||
thenify@3.3.1:
|
||||
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
||||
|
||||
tinyglobby@0.2.17:
|
||||
resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
to-object-path@0.3.0:
|
||||
resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3142,9 +3227,19 @@ packages:
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
ua-is-frozen@0.1.2:
|
||||
resolution: {integrity: sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==}
|
||||
|
||||
ua-parser-js@2.0.6:
|
||||
resolution: {integrity: sha512-EmaxXfltJaDW75SokrY4/lXMrVyXomE/0FpIIqP2Ctic93gK7rlme55Cwkz8l3YZ6gqf94fCU7AnIkidd/KXPg==}
|
||||
hasBin: true
|
||||
|
||||
uc.micro@2.1.0:
|
||||
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
||||
|
||||
ufo@1.6.4:
|
||||
resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}
|
||||
|
||||
unbox-primitive@1.1.0:
|
||||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -3164,6 +3259,53 @@ packages:
|
||||
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
unplugin-utils@0.3.2:
|
||||
resolution: {integrity: sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
unplugin-vue-components@32.1.0:
|
||||
resolution: {integrity: sha512-YiUkSxuRjab18XFOrX5VsIxXzccrfmHVGsGeJgSgklb829DQmCy9E4vvDUE4tuvZZdxyFJZX0Oc4TPnnxiiMyg==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
peerDependencies:
|
||||
'@nuxt/kit': ^3.2.2 || ^4.0.0
|
||||
vue: ^3.0.0
|
||||
peerDependenciesMeta:
|
||||
'@nuxt/kit':
|
||||
optional: true
|
||||
|
||||
unplugin@3.3.0:
|
||||
resolution: {integrity: sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
peerDependencies:
|
||||
'@farmfe/core': '*'
|
||||
'@rspack/core': '*'
|
||||
bun-types-no-globals: '*'
|
||||
esbuild: '*'
|
||||
rolldown: '*'
|
||||
rollup: '*'
|
||||
unloader: '*'
|
||||
vite: '*'
|
||||
webpack: '*'
|
||||
peerDependenciesMeta:
|
||||
'@farmfe/core':
|
||||
optional: true
|
||||
'@rspack/core':
|
||||
optional: true
|
||||
bun-types-no-globals:
|
||||
optional: true
|
||||
esbuild:
|
||||
optional: true
|
||||
rolldown:
|
||||
optional: true
|
||||
rollup:
|
||||
optional: true
|
||||
unloader:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
webpack:
|
||||
optional: true
|
||||
|
||||
unset-value@1.0.0:
|
||||
resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -3201,6 +3343,11 @@ packages:
|
||||
v8-compile-cache@2.4.0:
|
||||
resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==}
|
||||
|
||||
vant@4.9.22:
|
||||
resolution: {integrity: sha512-P2PDSj3oB6l3W1OpVlQpapeLmI6bXMSvPqPdrw5rutslC0Y6tSkrVB/iSD57weD7K92GsjGkvgDK0eZlOsXGqw==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
vary@1.1.2:
|
||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -3301,6 +3448,10 @@ packages:
|
||||
vue: ^3.5.12
|
||||
vue-router: ^4.2.2
|
||||
|
||||
vue3-emoji-picker@1.1.8:
|
||||
resolution: {integrity: sha512-k9tVHeQEBVLzVCLYAkFaI1nib3FJFQwdPhWD5khJkhks3ktg3g12z5wPGOSDpIuSLNtelRGvq1qdmZuJu5khfA==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
vue3-eslint@git+https://gitee.com/Cxx0822/vue3-eslint#849a4e0e783d3ecc57035fb2f92950998b6b2e41:
|
||||
resolution: {commit: 849a4e0e783d3ecc57035fb2f92950998b6b2e41, repo: https://gitee.com/Cxx0822/vue3-eslint, type: git}
|
||||
version: 1.0.0
|
||||
@@ -3329,6 +3480,9 @@ packages:
|
||||
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
webpack-virtual-modules@0.6.2:
|
||||
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
|
||||
|
||||
whatwg-mimetype@3.0.0:
|
||||
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -3812,12 +3966,19 @@ snapshots:
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
|
||||
'@jridgewell/remapping@2.3.5':
|
||||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.3.8
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
|
||||
'@jridgewell/resolve-uri@3.1.2': {}
|
||||
|
||||
'@jridgewell/set-array@1.2.1': {}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.0': {}
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
@@ -4366,6 +4527,14 @@ snapshots:
|
||||
'@typescript-eslint/types': 5.62.0
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@vant/auto-import-resolver@1.3.0': {}
|
||||
|
||||
'@vant/popperjs@1.3.0': {}
|
||||
|
||||
'@vant/use@1.6.0(vue@3.5.12(typescript@5.8.3))':
|
||||
dependencies:
|
||||
vue: 3.5.12(typescript@5.8.3)
|
||||
|
||||
'@vavt/util@2.1.0': {}
|
||||
|
||||
'@vitejs/plugin-vue@5.2.1(vite@5.2.0(@types/node@18.19.86)(sass@1.86.3))(vue@3.5.12(typescript@5.8.3))':
|
||||
@@ -4471,6 +4640,8 @@ snapshots:
|
||||
|
||||
'@vue/shared@3.5.13': {}
|
||||
|
||||
'@vue/shared@3.5.28': {}
|
||||
|
||||
'@vueuse/core@13.1.0(vue@3.5.12(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.21
|
||||
@@ -4507,13 +4678,15 @@ snapshots:
|
||||
dependencies:
|
||||
acorn: 7.4.1
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.14.1):
|
||||
acorn-jsx@5.3.2(acorn@8.15.0):
|
||||
dependencies:
|
||||
acorn: 8.14.1
|
||||
acorn: 8.15.0
|
||||
|
||||
acorn@7.4.1: {}
|
||||
|
||||
acorn@8.14.1: {}
|
||||
acorn@8.15.0: {}
|
||||
|
||||
acorn@8.18.0: {}
|
||||
|
||||
ajv@6.12.6:
|
||||
dependencies:
|
||||
@@ -4792,6 +4965,10 @@ snapshots:
|
||||
dependencies:
|
||||
readdirp: 4.1.2
|
||||
|
||||
chokidar@5.0.0:
|
||||
dependencies:
|
||||
readdirp: 5.0.0
|
||||
|
||||
class-utils@0.3.6:
|
||||
dependencies:
|
||||
arr-union: 3.1.0
|
||||
@@ -4851,6 +5028,10 @@ snapshots:
|
||||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
confbox@0.1.8: {}
|
||||
|
||||
confbox@0.2.4: {}
|
||||
|
||||
connect@3.7.0:
|
||||
dependencies:
|
||||
debug: 2.6.9
|
||||
@@ -4979,6 +5160,8 @@ snapshots:
|
||||
|
||||
delayed-stream@1.0.0: {}
|
||||
|
||||
detect-europe-js@0.1.2: {}
|
||||
|
||||
detect-libc@1.0.3:
|
||||
optional: true
|
||||
|
||||
@@ -5374,8 +5557,8 @@ snapshots:
|
||||
|
||||
espree@9.6.1:
|
||||
dependencies:
|
||||
acorn: 8.14.1
|
||||
acorn-jsx: 5.3.2(acorn@8.14.1)
|
||||
acorn: 8.15.0
|
||||
acorn-jsx: 5.3.2(acorn@8.15.0)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
esprima@4.0.1: {}
|
||||
@@ -5410,6 +5593,8 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
exsolve@1.1.1: {}
|
||||
|
||||
extend-shallow@2.0.1:
|
||||
dependencies:
|
||||
is-extendable: 0.1.1
|
||||
@@ -5452,6 +5637,10 @@ snapshots:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.5):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.5
|
||||
|
||||
file-entry-cache@6.0.1:
|
||||
dependencies:
|
||||
flat-cache: 3.2.0
|
||||
@@ -5684,6 +5873,8 @@ snapshots:
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.2
|
||||
|
||||
idb@7.1.1: {}
|
||||
|
||||
ignore@4.0.6: {}
|
||||
|
||||
ignore@5.3.2: {}
|
||||
@@ -5835,6 +6026,8 @@ snapshots:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
|
||||
is-standalone-pwa@0.1.1: {}
|
||||
|
||||
is-string@1.1.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
@@ -5949,6 +6142,12 @@ snapshots:
|
||||
emojis-list: 3.0.0
|
||||
json5: 1.0.2
|
||||
|
||||
local-pkg@1.2.1:
|
||||
dependencies:
|
||||
mlly: 1.8.2
|
||||
pkg-types: 2.3.1
|
||||
quansync: 0.2.11
|
||||
|
||||
lodash-es@4.17.21: {}
|
||||
|
||||
lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21):
|
||||
@@ -5973,6 +6172,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
|
||||
magic-string@0.30.21:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
map-cache@0.2.2: {}
|
||||
|
||||
map-visit@1.0.0:
|
||||
@@ -6075,6 +6278,13 @@ snapshots:
|
||||
for-in: 1.0.2
|
||||
is-extendable: 1.0.1
|
||||
|
||||
mlly@1.8.2:
|
||||
dependencies:
|
||||
acorn: 8.18.0
|
||||
pathe: 2.0.3
|
||||
pkg-types: 1.3.1
|
||||
ufo: 1.6.4
|
||||
|
||||
mockjs@1.1.0:
|
||||
dependencies:
|
||||
commander: 13.1.0
|
||||
@@ -6179,6 +6389,8 @@ snapshots:
|
||||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
obug@2.1.4: {}
|
||||
|
||||
on-finished@2.3.0:
|
||||
dependencies:
|
||||
ee-first: 1.1.1
|
||||
@@ -6231,10 +6443,14 @@ snapshots:
|
||||
|
||||
pathe@0.2.0: {}
|
||||
|
||||
pathe@2.0.3: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
picomatch@4.0.5: {}
|
||||
|
||||
pify@2.3.0: {}
|
||||
|
||||
pinia@2.3.1(typescript@5.8.3)(vue@3.5.12(typescript@5.8.3)):
|
||||
@@ -6249,6 +6465,18 @@ snapshots:
|
||||
|
||||
pirates@4.0.7: {}
|
||||
|
||||
pkg-types@1.3.1:
|
||||
dependencies:
|
||||
confbox: 0.1.8
|
||||
mlly: 1.8.2
|
||||
pathe: 2.0.3
|
||||
|
||||
pkg-types@2.3.1:
|
||||
dependencies:
|
||||
confbox: 0.2.4
|
||||
exsolve: 1.1.1
|
||||
pathe: 2.0.3
|
||||
|
||||
posix-character-classes@0.1.1: {}
|
||||
|
||||
possible-typed-array-names@1.1.0: {}
|
||||
@@ -6340,6 +6568,8 @@ snapshots:
|
||||
dependencies:
|
||||
side-channel: 1.1.0
|
||||
|
||||
quansync@0.2.11: {}
|
||||
|
||||
query-string@4.3.4:
|
||||
dependencies:
|
||||
object-assign: 4.1.1
|
||||
@@ -6363,6 +6593,8 @@ snapshots:
|
||||
|
||||
readdirp@4.1.2: {}
|
||||
|
||||
readdirp@5.0.0: {}
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
@@ -6768,6 +7000,11 @@ snapshots:
|
||||
dependencies:
|
||||
any-promise: 1.3.0
|
||||
|
||||
tinyglobby@0.2.17:
|
||||
dependencies:
|
||||
fdir: 6.5.0(picomatch@4.0.5)
|
||||
picomatch: 4.0.5
|
||||
|
||||
to-object-path@0.3.0:
|
||||
dependencies:
|
||||
kind-of: 3.2.2
|
||||
@@ -6866,8 +7103,18 @@ snapshots:
|
||||
|
||||
typescript@5.8.3: {}
|
||||
|
||||
ua-is-frozen@0.1.2: {}
|
||||
|
||||
ua-parser-js@2.0.6:
|
||||
dependencies:
|
||||
detect-europe-js: 0.1.2
|
||||
is-standalone-pwa: 0.1.1
|
||||
ua-is-frozen: 0.1.2
|
||||
|
||||
uc.micro@2.1.0: {}
|
||||
|
||||
ufo@1.6.4: {}
|
||||
|
||||
unbox-primitive@1.1.0:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
@@ -6888,6 +7135,44 @@ snapshots:
|
||||
|
||||
unpipe@1.0.0: {}
|
||||
|
||||
unplugin-utils@0.3.2:
|
||||
dependencies:
|
||||
pathe: 2.0.3
|
||||
picomatch: 4.0.5
|
||||
|
||||
unplugin-vue-components@32.1.0(esbuild@0.20.2)(rollup@4.40.0)(vite@5.2.0(@types/node@18.19.86)(sass@1.86.3))(vue@3.5.12(typescript@5.8.3)):
|
||||
dependencies:
|
||||
chokidar: 5.0.0
|
||||
local-pkg: 1.2.1
|
||||
magic-string: 0.30.21
|
||||
mlly: 1.8.2
|
||||
obug: 2.1.4
|
||||
picomatch: 4.0.5
|
||||
tinyglobby: 0.2.17
|
||||
unplugin: 3.3.0(esbuild@0.20.2)(rollup@4.40.0)(vite@5.2.0(@types/node@18.19.86)(sass@1.86.3))
|
||||
unplugin-utils: 0.3.2
|
||||
vue: 3.5.12(typescript@5.8.3)
|
||||
transitivePeerDependencies:
|
||||
- '@farmfe/core'
|
||||
- '@rspack/core'
|
||||
- bun-types-no-globals
|
||||
- esbuild
|
||||
- rolldown
|
||||
- rollup
|
||||
- unloader
|
||||
- vite
|
||||
- webpack
|
||||
|
||||
unplugin@3.3.0(esbuild@0.20.2)(rollup@4.40.0)(vite@5.2.0(@types/node@18.19.86)(sass@1.86.3)):
|
||||
dependencies:
|
||||
'@jridgewell/remapping': 2.3.5
|
||||
picomatch: 4.0.5
|
||||
webpack-virtual-modules: 0.6.2
|
||||
optionalDependencies:
|
||||
esbuild: 0.20.2
|
||||
rollup: 4.40.0
|
||||
vite: 5.2.0(@types/node@18.19.86)(sass@1.86.3)
|
||||
|
||||
unset-value@1.0.0:
|
||||
dependencies:
|
||||
has-value: 0.3.1
|
||||
@@ -6924,6 +7209,13 @@ snapshots:
|
||||
|
||||
v8-compile-cache@2.4.0: {}
|
||||
|
||||
vant@4.9.22(vue@3.5.12(typescript@5.8.3)):
|
||||
dependencies:
|
||||
'@vant/popperjs': 1.3.0
|
||||
'@vant/use': 1.6.0(vue@3.5.12(typescript@5.8.3))
|
||||
'@vue/shared': 3.5.28
|
||||
vue: 3.5.12(typescript@5.8.3)
|
||||
|
||||
vary@1.1.2: {}
|
||||
|
||||
vfonts@0.0.3: {}
|
||||
@@ -7027,6 +7319,14 @@ snapshots:
|
||||
vue: 3.5.12(typescript@5.8.3)
|
||||
vue-router: 4.5.1(vue@3.5.12(typescript@5.8.3))
|
||||
|
||||
vue3-emoji-picker@1.1.8(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@popperjs/core': 2.11.8
|
||||
idb: 7.1.1
|
||||
vue: 3.5.12(typescript@5.8.3)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
vue3-eslint@git+https://gitee.com/Cxx0822/vue3-eslint#849a4e0e783d3ecc57035fb2f92950998b6b2e41(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)(typescript@5.8.3))(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint-config-standard@16.0.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0))(eslint-plugin-node@11.1.0(eslint@7.32.0))(eslint-plugin-promise@5.2.0(eslint@7.32.0))(eslint@7.32.0))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0))(eslint-plugin-node@11.1.0(eslint@7.32.0))(eslint-plugin-promise@5.2.0(eslint@7.32.0))(eslint-plugin-vue@8.7.1(eslint@7.32.0))(eslint@7.32.0):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.8.3))(eslint@7.32.0)(typescript@5.8.3)
|
||||
@@ -7052,6 +7352,8 @@ snapshots:
|
||||
|
||||
webidl-conversions@7.0.0: {}
|
||||
|
||||
webpack-virtual-modules@0.6.2: {}
|
||||
|
||||
whatwg-mimetype@3.0.0: {}
|
||||
|
||||
which-boxed-primitive@1.1.1:
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import AppLoading from '@/components/AppLoading.vue'
|
||||
import AppLoading from '@/components/Common/AppLoading.vue'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { cloudService } from './index'
|
||||
import { IAccount } from '@/types/auth.ts'
|
||||
|
||||
export const queryAccountApi = (): Promise<IAccount[]> =>
|
||||
cloudService({
|
||||
url: '/admin-service/account',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const registerAccountApi = (account: IAccount): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/admin-service/account',
|
||||
method: 'post',
|
||||
data: account
|
||||
})
|
||||
|
||||
export const deleteAccountApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/admin-service/account/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const updateAccountPasswordApi = (id: number,
|
||||
oldPassword: string, newPassword: string): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/admin-service/account/password/${id}`,
|
||||
method: 'put',
|
||||
params: { oldPassword, newPassword }
|
||||
})
|
||||
@@ -4,33 +4,33 @@ import { IStatsChart } from 'vue3-common/types'
|
||||
|
||||
export const addAnniversaryApi = (anniversary: IAnniversary): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/anniversary',
|
||||
url: '/home-api/anniversary',
|
||||
method: 'post',
|
||||
data: anniversary
|
||||
})
|
||||
|
||||
export const updateAnniversaryApi = (id: number, anniversary: IAnniversary): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/anniversary/${id}`,
|
||||
url: `/home-api/anniversary/${id}`,
|
||||
method: 'put',
|
||||
data: anniversary
|
||||
})
|
||||
|
||||
export const deleteAnniversaryApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/anniversary/${id}`,
|
||||
url: `/home-api/anniversary/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryAnniversaryApi = (category: string): Promise<IAnniversary[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/anniversary',
|
||||
url: '/home-api/anniversary',
|
||||
method: 'get',
|
||||
params: { category }
|
||||
})
|
||||
|
||||
export const queryAnniversaryCategoryApi = (): Promise<IStatsChart[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/anniversary/category',
|
||||
url: '/home-api/anniversary/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -3,33 +3,33 @@ import { IAssetRecord } from '@/types/asset'
|
||||
|
||||
export const addAssetApi = (asset: IAssetRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/asset',
|
||||
url: '/home-api/asset',
|
||||
method: 'post',
|
||||
data: asset
|
||||
})
|
||||
|
||||
export const updateAssetApi = (id: number, asset: IAssetRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/asset/${id}`,
|
||||
url: `/home-api/asset/${id}`,
|
||||
method: 'put',
|
||||
data: asset
|
||||
})
|
||||
|
||||
export const deleteAssetApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/asset/${id}`,
|
||||
url: `/home-api/asset/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryAssetApi = (category: string): Promise<IAssetRecord[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/asset',
|
||||
url: '/home-api/asset',
|
||||
method: 'get',
|
||||
params: { category }
|
||||
})
|
||||
|
||||
export const queryAssetCategoryApi = (): Promise<string[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/asset/category',
|
||||
url: '/home-api/asset/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
35
src/apis/award.ts
Normal file
35
src/apis/award.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { cloudService } from './index'
|
||||
import { IAward, IAwardQuery } from '@/types/award.ts'
|
||||
|
||||
export const addAwardApi = (award: IAward): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-api/award',
|
||||
method: 'post',
|
||||
data: award
|
||||
})
|
||||
|
||||
export const updateAwardApi = (id: number, award: IAward): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-api/award/${id}`,
|
||||
method: 'put',
|
||||
data: award
|
||||
})
|
||||
|
||||
export const deleteAwardApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-api/award/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryAwardApi = (id: number): Promise<IAward> =>
|
||||
cloudService({
|
||||
url: `/home-api/award/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryAwardListApi = (query: IAwardQuery): Promise<IAward[]> =>
|
||||
cloudService({
|
||||
url: '/home-api/award',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
@@ -4,106 +4,113 @@ import {
|
||||
IBillCategory,
|
||||
IBillPay,
|
||||
IBillQuery,
|
||||
IBillRecord,
|
||||
IBillRecord, IBillSearch
|
||||
} from '@/types/bill'
|
||||
import { IStatsChart } from 'vue3-common/dist/types'
|
||||
|
||||
export const addBillRecordApi = (billRecord: IBillRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/bill',
|
||||
url: '/home-api/bill',
|
||||
method: 'post',
|
||||
data: billRecord
|
||||
})
|
||||
|
||||
export const updateBillRecordApi = (id: number, billRecord: IBillRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/bill/${id}`,
|
||||
url: `/home-api/bill/${id}`,
|
||||
method: 'put',
|
||||
data: billRecord
|
||||
})
|
||||
|
||||
export const deleteBillRecordApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/bill/${id}`,
|
||||
url: `/home-api/bill/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
export const queryBillRecordApi = (id: number): Promise<IBillRecord> =>
|
||||
cloudService({
|
||||
url: `/home-service/bill/${id}`,
|
||||
url: `/home-api/bill/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBillSummaryApi = (query: IBillQuery): Promise<IBillRecord[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/bill/summary',
|
||||
url: '/home-api/bill/summary',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
|
||||
export const searchBillSummaryApi = (search: IBillSearch): Promise<IBillRecord[]> =>
|
||||
cloudService({
|
||||
url: '/home-api/bill/search',
|
||||
method: 'get',
|
||||
params: search
|
||||
})
|
||||
|
||||
export const queryBillStatsApi = (type: string, query: IBillQuery): Promise<IStatsChart[]> =>
|
||||
cloudService({
|
||||
url: `/home-service/bill/stats/${type}`,
|
||||
url: `/home-api/bill/stats/${type}`,
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
|
||||
export const queryBillPayApi = (): Promise<IBillPay[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/bill/pay',
|
||||
url: '/home-api/bill/pay',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBillBookApi = (): Promise<IBillBook[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/bill/book',
|
||||
url: '/home-api/bill/book',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBillCategoryApi = (): Promise<IBillCategory[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/bill/category',
|
||||
url: '/home-api/bill/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const addBillPayApi = (billPay: IBillPay): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/bill-manage/pay',
|
||||
url: '/home-api/bill-manage/pay',
|
||||
method: 'post',
|
||||
data: billPay
|
||||
})
|
||||
|
||||
export const updateBillPayApi = (id: number, billPay: IBillPay): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/bill-manage/pay/${id}`,
|
||||
url: `/home-api/bill-manage/pay/${id}`,
|
||||
method: 'put',
|
||||
data: billPay
|
||||
})
|
||||
|
||||
export const addBillBookApi = (billBook: IBillBook): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/bill-manage/book',
|
||||
url: '/home-api/bill-manage/book',
|
||||
method: 'post',
|
||||
data: billBook
|
||||
})
|
||||
|
||||
export const updateBillBookApi = (id: number, billBook: IBillBook): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/bill-manage/book/${id}`,
|
||||
url: `/home-api/bill-manage/book/${id}`,
|
||||
method: 'put',
|
||||
data: billBook
|
||||
})
|
||||
|
||||
export const addBillCategoryApi = (billCategory: IBillCategory): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/bill-manage/category',
|
||||
url: '/home-api/bill-manage/category',
|
||||
method: 'post',
|
||||
data: billCategory
|
||||
})
|
||||
|
||||
export const updateBillCategoryApi = (id: number, billCategory: IBillCategory): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/bill-manage/category/${id}`,
|
||||
url: `/home-api/bill-manage/category/${id}`,
|
||||
method: 'put',
|
||||
data: billCategory
|
||||
})
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import { cloudService } from './index'
|
||||
import { IBlog, IBlogCategory, IBlogStats, INewBlog, IQueryBlog } from '@/types/blog'
|
||||
import { IBlog, IBlogCategory, IBlogComment, IBlogStats, IQueryBlog } from '@/types/blog'
|
||||
|
||||
import qs from 'qs'
|
||||
import { IPageRecord } from '@/types'
|
||||
|
||||
export const queryBlogApi = (currentPage: number, pageSize: number): Promise<any> =>
|
||||
export const queryBlogApi = (currentPage: number, pageSize: number): Promise<IPageRecord<IBlog>> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/page',
|
||||
url: '/blog-api/blog/page',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize }
|
||||
})
|
||||
|
||||
export const queryBlogByConditionApi = (query: IQueryBlog): Promise<IBlog[]> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/condition',
|
||||
url: '/blog-api/blog/condition',
|
||||
method: 'get',
|
||||
params: query,
|
||||
paramsSerializer: (params) => {
|
||||
@@ -22,70 +23,30 @@ export const queryBlogByConditionApi = (query: IQueryBlog): Promise<IBlog[]> =>
|
||||
|
||||
export const queryBlogByIdApi = (id: number): Promise<IBlog> =>
|
||||
cloudService({
|
||||
url: `/blog-service/blog/content/${id}`,
|
||||
url: `/blog-api/blog/${id}/content`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBlogCategoryApi = (): Promise<IBlogCategory[]> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/category',
|
||||
url: '/blog-api/blog/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBlogStatsApi = (): Promise<IBlogStats> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/stats',
|
||||
url: '/blog-api/blog/stats',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryLatestBlogApi = (): Promise<IBlog[]> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/latest',
|
||||
url: '/blog-api/blog/latest',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryAdminBlogApi = (currentPage: number, pageSize: number): Promise<any> =>
|
||||
export const queryBlogCommentApi = (blogId: number): Promise<IBlogComment[]> =>
|
||||
cloudService({
|
||||
url: '/admin-service/blog-manage/page',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize }
|
||||
})
|
||||
|
||||
export const queryAdminBlogByIdApi = (id: number): Promise<IBlog> =>
|
||||
cloudService({
|
||||
url: `/admin-service/blog-manage/content/${id}`,
|
||||
url: `/blog-api/blog/${blogId}/comment`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryAdminBlogCategoryApi = (): Promise<IBlogCategory[]> =>
|
||||
cloudService({
|
||||
url: '/admin-service/blog-manage/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const addBlogApi = (blog: INewBlog): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/admin-service/blog-manage',
|
||||
method: 'post',
|
||||
data: blog
|
||||
})
|
||||
|
||||
export const updateBlogApi = (id: number, blog: INewBlog): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/admin-service/blog-manage/${id}`,
|
||||
method: 'put',
|
||||
data: blog
|
||||
})
|
||||
|
||||
export const deleteBlogApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/admin-service/blog-manage/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
export const queryBlogVisitApi = (currentPage: number, pageSize: number): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/admin-service/blog-manage/visit',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize }
|
||||
})
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { cloudService } from './index'
|
||||
import { IBudgetInfo } from '@/types/budget'
|
||||
|
||||
export const addBudgetApi = (budget: IBudgetInfo): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/budget',
|
||||
method: 'post',
|
||||
data: budget
|
||||
})
|
||||
|
||||
export const updateBudgetApi = (id: number, budget: IBudgetInfo): Promise<any> =>
|
||||
cloudService({
|
||||
url: `/home-service/budget/${id}`,
|
||||
method: 'put',
|
||||
data: budget
|
||||
})
|
||||
|
||||
export const deleteBudgetApi = (id: number): Promise<any> =>
|
||||
cloudService({
|
||||
url: `/home-service/budget/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
export const queryBudgetApi = (category: string): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/budget',
|
||||
method: 'get',
|
||||
params: { category }
|
||||
})
|
||||
|
||||
export const queryBudgetCategory = (): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/budget/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBudgetRankStats = (category: string): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/budget/stats/rank',
|
||||
method: 'get',
|
||||
params: { category }
|
||||
})
|
||||
|
||||
export const queryBudgetProjectStats = (category: string): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/budget/stats/project',
|
||||
method: 'get',
|
||||
params: { category }
|
||||
})
|
||||
29
src/apis/car.ts
Normal file
29
src/apis/car.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { cloudService } from './index'
|
||||
import { ICarEvent, ICarEventQuery } from '@/types/car.ts'
|
||||
|
||||
export const addCarEventApi = (carEvent: ICarEvent): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-api/car',
|
||||
method: 'post',
|
||||
data: carEvent
|
||||
})
|
||||
|
||||
export const updateCarEventApi = (id: number, carEvent: ICarEvent): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-api/car/${id}`,
|
||||
method: 'put',
|
||||
data: carEvent
|
||||
})
|
||||
|
||||
export const deleteCarEventApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-api/car/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryCarEventListApi = (query: ICarEventQuery): Promise<ICarEvent[]> =>
|
||||
cloudService({
|
||||
url: '/home-api/car',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
@@ -1,9 +1,10 @@
|
||||
import { cloudService } from './index'
|
||||
import { IFileInfo } from '@/types/file'
|
||||
import type { AxiosProgressEvent } from 'axios'
|
||||
|
||||
export const uploadFileApi = (form: FormData, path: string, md5: string): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/file',
|
||||
url: '/home-api/file',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
@@ -12,38 +13,22 @@ export const uploadFileApi = (form: FormData, path: string, md5: string): Promis
|
||||
data: form
|
||||
})
|
||||
|
||||
/**
|
||||
* 上传图片到Hello图床
|
||||
* @param form 表单
|
||||
* @param token token
|
||||
*/
|
||||
export const uploadHelloImageApi = (form: FormData, token: string): Promise<any> =>
|
||||
export const uploadAListFileApi = (form: FormData,
|
||||
progress: (event: AxiosProgressEvent) => void): Promise<string> =>
|
||||
cloudService({
|
||||
url: '/hello-service/upload',
|
||||
url: '/home-api/file/alist',
|
||||
headers: {
|
||||
Authorization: token,
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress: progress,
|
||||
timeout: 0,
|
||||
method: 'post',
|
||||
data: form
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取Hello图床相册
|
||||
* @param token token
|
||||
*/
|
||||
export const getHelloAlbumsApi = (token: string): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/hello-service/albums',
|
||||
headers: {
|
||||
Authorization: token
|
||||
},
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const getFolderInfoApi = (folderName: string): Promise<IFileInfo[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/file/catalog',
|
||||
url: '/home-api/file/catalog',
|
||||
method: 'get',
|
||||
params: { folderName }
|
||||
})
|
||||
|
||||
@@ -1,81 +1,89 @@
|
||||
import { cloudService } from './index'
|
||||
import { IFoodQuery, IFoodRecipe, IFoodRecord, IFoodStats } from '@/types/food'
|
||||
import { IPageRecord } from '@/types'
|
||||
|
||||
export const addFoodRecipeApi = (foodRecipe: IFoodRecipe): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/food/recipe',
|
||||
url: '/home-api/food/recipe',
|
||||
method: 'post',
|
||||
data: foodRecipe
|
||||
})
|
||||
|
||||
export const updateFoodRecipeApi = (id: number, foodRecipe: IFoodRecipe): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/food/recipe/${id}`,
|
||||
url: `/home-api/food/recipe/${id}`,
|
||||
method: 'put',
|
||||
data: foodRecipe
|
||||
})
|
||||
|
||||
export const deleteFoodRecipeApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/food/recipe/${id}`,
|
||||
url: `/home-api/food/recipe/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
export const queryFoodRecipeByIdApi = (id: number): Promise<any> =>
|
||||
export const queryFoodRecipeByIdApi = (id: number): Promise<IFoodRecipe> =>
|
||||
cloudService({
|
||||
url: `/home-service/food/recipe/${id}`,
|
||||
url: `/home-api/food/recipe/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryFoodRecipeApi = (currentPage: number, pageSize: number,
|
||||
query: IFoodQuery): Promise<any> =>
|
||||
query: IFoodQuery): Promise<IPageRecord<IFoodRecipe>> =>
|
||||
cloudService({
|
||||
url: '/home-service/food/recipe/page',
|
||||
url: '/home-api/food/recipe/page',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize, ...query }
|
||||
})
|
||||
|
||||
export const searchFoodRecipeApi = (name: string): Promise<IFoodRecipe> =>
|
||||
cloudService({
|
||||
url: '/home-api/food/recipe/search',
|
||||
method: 'get',
|
||||
params: { name }
|
||||
})
|
||||
|
||||
export const queryFoodNameListApi = (): Promise<string[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/food/recipe/name',
|
||||
url: '/home-api/food/recipe/name',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const addFoodRecordApi = (foodRecord: IFoodRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/food/record',
|
||||
url: '/home-api/food/record',
|
||||
method: 'post',
|
||||
data: foodRecord
|
||||
})
|
||||
|
||||
export const updateFoodRecordApi = (id: number, foodRecord: IFoodRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/food/record/${id}`,
|
||||
url: `/home-api/food/record/${id}`,
|
||||
method: 'put',
|
||||
data: foodRecord
|
||||
})
|
||||
|
||||
export const deleteFoodRecordApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/food/record/${id}`,
|
||||
url: `/home-api/food/record/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
export const queryFoodRecordApi = (startDate: string, endDate: string): Promise<IFoodRecord[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/food/record',
|
||||
url: '/home-api/food/record',
|
||||
method: 'get',
|
||||
params: { startDate, endDate }
|
||||
})
|
||||
|
||||
export const queryFoodCategoryApi = (): Promise<string[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/food/category',
|
||||
url: '/home-api/food/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryFoodStatsApi = (): Promise<IFoodStats> =>
|
||||
cloudService({
|
||||
url: '/home-service/food/stats',
|
||||
url: '/home-api/food/stats',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
16
src/apis/health.ts
Normal file
16
src/apis/health.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { cloudService } from './index'
|
||||
import { IHealth, IHealthQuery } from '@/types/health'
|
||||
|
||||
export const updateHealthApi = (id: number, health: IHealth): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-api/health/${id}`,
|
||||
method: 'put',
|
||||
data: health
|
||||
})
|
||||
|
||||
export const queryHealthApi = (query: IHealthQuery): Promise<IHealth[]> =>
|
||||
cloudService({
|
||||
url: '/home-api/health',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
@@ -4,33 +4,33 @@ import { IJournal, IJournalQuery } from '@/types/journal.ts'
|
||||
|
||||
export const addJournalApi = (journal: IJournal): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/journal',
|
||||
url: '/home-api/journal',
|
||||
method: 'post',
|
||||
data: journal
|
||||
})
|
||||
|
||||
export const updateJournalApi = (id: number, journal: IJournal): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/journal/${id}`,
|
||||
url: `/home-api/journal/${id}`,
|
||||
method: 'put',
|
||||
data: journal
|
||||
})
|
||||
|
||||
export const deleteJournalApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/journal/${id}`,
|
||||
url: `/home-api/journal/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryJournalApi = (query: IJournalQuery): Promise<IJournal[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/journal',
|
||||
url: '/home-api/journal',
|
||||
method: 'get',
|
||||
params: { ...query }
|
||||
})
|
||||
|
||||
export const queryJournalCategoryApi = (): Promise<IStatsChart[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/journal/category',
|
||||
url: '/home-api/journal/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -3,27 +3,27 @@ import { IKpi, IKpiQuery } from '@/types/kpi'
|
||||
|
||||
export const addKpiApi = (kpi: IKpi): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/kpi',
|
||||
url: '/home-api/kpi',
|
||||
method: 'post',
|
||||
data: kpi
|
||||
})
|
||||
|
||||
export const updateKpiApi = (id: number, kpi: IKpi): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/kpi/${id}`,
|
||||
url: `/home-api/kpi/${id}`,
|
||||
method: 'put',
|
||||
data: kpi
|
||||
})
|
||||
|
||||
export const deleteKpiApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/kpi/${id}`,
|
||||
url: `/home-api/kpi/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryKpiApi = (query: IKpiQuery): Promise<IKpi[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/kpi',
|
||||
url: '/home-api/kpi',
|
||||
method: 'get',
|
||||
params: { ...query }
|
||||
})
|
||||
|
||||
@@ -3,33 +3,33 @@ import { ILedgerRecord } from '@/types/ledger'
|
||||
|
||||
export const addLedgerApi = (ledger: ILedgerRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/ledger',
|
||||
url: '/home-api/ledger',
|
||||
method: 'post',
|
||||
data: ledger
|
||||
})
|
||||
|
||||
export const updateLedgerApi = (id: number, ledger: ILedgerRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/ledger/${id}`,
|
||||
url: `/home-api/ledger/${id}`,
|
||||
method: 'put',
|
||||
data: ledger
|
||||
})
|
||||
|
||||
export const deleteLedgerApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/ledger/${id}`,
|
||||
url: `/home-api/ledger/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryLedgerApi = (book: string): Promise<ILedgerRecord[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/ledger',
|
||||
url: '/home-api/ledger',
|
||||
method: 'get',
|
||||
params: { book }
|
||||
})
|
||||
|
||||
export const queryLedgerBookApi = (): Promise<string[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/ledger/book',
|
||||
url: '/home-api/ledger/book',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import { cloudService } from './index'
|
||||
import { IPassword, IQueryPassword } from '@/types/password'
|
||||
import { IPassword, IPasswordQuery } from '@/types/password'
|
||||
|
||||
export const addPasswordApi = (password: IPassword): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/password',
|
||||
url: '/home-api/password',
|
||||
method: 'post',
|
||||
data: password
|
||||
})
|
||||
|
||||
export const updatePasswordApi = (id: number, password: IPassword): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/password/${id}`,
|
||||
url: `/home-api/password/${id}`,
|
||||
method: 'put',
|
||||
data: password
|
||||
})
|
||||
|
||||
export const deletePasswordApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/password/${id}`,
|
||||
url: `/home-api/password/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryPasswordApi = (query: IQueryPassword): Promise<IPassword[]> =>
|
||||
export const queryPasswordApi = (query: IPasswordQuery): Promise<IPassword[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/password',
|
||||
url: '/home-api/password',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
|
||||
export const queryPasswordCategoryApi = (): Promise<string[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/password/category',
|
||||
url: '/home-api/password/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -1,37 +1,43 @@
|
||||
import { cloudService } from './index'
|
||||
import { IPeriodDay, IPeriodSetting } from '@/types/period.ts'
|
||||
import { IMenstrualPeriod, IPeriodDay, IPeriodSetting } from '@/types/period.ts'
|
||||
|
||||
|
||||
export const updatePeriodDayApi = (id: number, periodDay: IPeriodDay): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/period/day/${id}`,
|
||||
url: `/home-api/period/day/${id}`,
|
||||
method: 'put',
|
||||
data: periodDay
|
||||
})
|
||||
|
||||
export const queryPeriodDayApi = (month: string): Promise<IPeriodDay[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/period/day',
|
||||
url: '/home-api/period/day',
|
||||
method: 'get',
|
||||
params: { month }
|
||||
})
|
||||
|
||||
export const getMenstrualDaysApi = (): Promise<IMenstrualPeriod[]> =>
|
||||
cloudService({
|
||||
url: '/home-api/period//menstruate/days',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const getMenstruateFirstDateApi = (month: string): Promise<string> =>
|
||||
cloudService({
|
||||
url: '/home-service/period/menstruate',
|
||||
url: '/home-api/period/menstruate',
|
||||
method: 'get',
|
||||
params: { month }
|
||||
})
|
||||
|
||||
export const updatePeriodSettingApi = (id: number, setting: IPeriodSetting): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/period/setting/${id}`,
|
||||
url: `/home-api/period/setting/${id}`,
|
||||
method: 'put',
|
||||
data: setting
|
||||
})
|
||||
|
||||
export const queryPeriodSettingApi = (): Promise<IPeriodSetting> =>
|
||||
cloudService({
|
||||
url: '/home-service/period/setting',
|
||||
url: '/home-api/period/setting',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -3,40 +3,40 @@ import { IPlanInfo, IPlanQuery } from '@/types/plan.ts'
|
||||
|
||||
export const addPlanApi = (plan: IPlanInfo): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/plan',
|
||||
url: '/home-api/plan',
|
||||
method: 'post',
|
||||
data: plan
|
||||
})
|
||||
|
||||
export const updatePlanApi = (id: number, plan: IPlanInfo): Promise<any> =>
|
||||
cloudService({
|
||||
url: `/home-service/plan/${id}`,
|
||||
url: `/home-api/plan/${id}`,
|
||||
method: 'put',
|
||||
data: plan
|
||||
})
|
||||
|
||||
export const setPlanStatusApi = (id: number, status: boolean): Promise<any> =>
|
||||
cloudService({
|
||||
url: `/home-service/plan/${id}/status`,
|
||||
url: `/home-api/plan/${id}/status`,
|
||||
method: 'put',
|
||||
params: { status }
|
||||
})
|
||||
|
||||
export const deletePlanApi = (id: number): Promise<any> =>
|
||||
cloudService({
|
||||
url: `/home-service/plan/${id}`,
|
||||
url: `/home-api/plan/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryPlanApi = (query: IPlanQuery): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/plan',
|
||||
url: '/home-api/plan',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
|
||||
export const queryPlanStatsApi = (): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/plan/stats',
|
||||
url: '/home-api/plan/stats',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
import { cloudService } from './index'
|
||||
import { IProduct, IQueryProduct } from '@/types/product.ts'
|
||||
import { IProduct, IProductQuery } from '@/types/product.ts'
|
||||
|
||||
export const addProductApi = (product: IProduct): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/product',
|
||||
url: '/home-api/product',
|
||||
method: 'post',
|
||||
data: product
|
||||
})
|
||||
|
||||
export const updateProductApi = (id: number, product: IProduct): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/product/${id}`,
|
||||
url: `/home-api/product/${id}`,
|
||||
method: 'put',
|
||||
data: product
|
||||
})
|
||||
|
||||
export const deleteProductApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/product/${id}`,
|
||||
url: `/home-api/product/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
|
||||
export const queryProductApi = (id: number): Promise<IProduct> =>
|
||||
cloudService({
|
||||
url: `/home-service/product/${id}`,
|
||||
url: `/home-api/product/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryProductListApi = (query: IQueryProduct): Promise<IProduct[]> =>
|
||||
export const queryProductListApi = (query: IProductQuery): Promise<IProduct[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/product',
|
||||
url: '/home-api/product',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
|
||||
export const queryProductCategoryApi = (): Promise<string[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/product/category',
|
||||
url: '/home-api/product/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -3,6 +3,6 @@ import { IQuartzInfo } from '@/types/quartz'
|
||||
|
||||
export const queryQuartzApi = (): Promise<IQuartzInfo[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/quartz',
|
||||
url: '/home-api/quartz',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -3,14 +3,14 @@ import { ISession } from '@/types/auth'
|
||||
|
||||
export const loginHomeApi = (name: string, password: string): Promise<ISession> =>
|
||||
cloudService({
|
||||
url: '/home-service/session',
|
||||
url: '/home-api/session',
|
||||
method: 'post',
|
||||
params: { name, password }
|
||||
})
|
||||
|
||||
export const loginAdminApi = (name: string, password: string): Promise<ISession> =>
|
||||
cloudService({
|
||||
url: '/admin-service/session',
|
||||
url: '/admin-api/session',
|
||||
method: 'post',
|
||||
params: { name, password }
|
||||
})
|
||||
|
||||
@@ -3,80 +3,80 @@ import { ITravelQuery, ITravelRecord, ITravelSpot, ITravelStats } from '@/types/
|
||||
|
||||
export const addTravelSpotApi = (travelSpot: ITravelSpot): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/travel/spot',
|
||||
url: '/home-api/travel/spot',
|
||||
method: 'post',
|
||||
data: travelSpot
|
||||
})
|
||||
|
||||
export const updateTravelSpotApi = (id: number, travelSpot: ITravelSpot): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/travel/spot/${id}`,
|
||||
url: `/home-api/travel/spot/${id}`,
|
||||
method: 'put',
|
||||
data: travelSpot
|
||||
})
|
||||
|
||||
export const deleteTravelSpotApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/travel/spot/${id}`,
|
||||
url: `/home-api/travel/spot/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
export const queryTravelSpotApi = (id: number): Promise<ITravelSpot> =>
|
||||
cloudService({
|
||||
url: `/home-service/travel/spot/${id}`,
|
||||
url: `/home-api/travel/spot/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryTravelSpotListApi = (currentPage: number, pageSize: number,
|
||||
query: ITravelQuery): Promise<any> =>
|
||||
cloudService({
|
||||
url: '/home-service/travel/spot/page',
|
||||
url: '/home-api/travel/spot/page',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize, ...query }
|
||||
})
|
||||
|
||||
export const queryTravelSpotNameListApi = (): Promise<string[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/travel/spot/name',
|
||||
url: '/home-api/travel/spot/name',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const addTravelRecordApi = (travelRecord: ITravelRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/home-service/travel/record',
|
||||
url: '/home-api/travel/record',
|
||||
method: 'post',
|
||||
data: travelRecord
|
||||
})
|
||||
|
||||
export const updateTravelRecordApi = (id: number, travelRecord: ITravelRecord): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/travel/record/${id}`,
|
||||
url: `/home-api/travel/record/${id}`,
|
||||
method: 'put',
|
||||
data: travelRecord
|
||||
})
|
||||
|
||||
export const deleteTravelRecordApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/travel/record/${id}`,
|
||||
url: `/home-api/travel/record/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
export const queryTravelRecordApi = (startDate: string, endDate: string):
|
||||
Promise<ITravelRecord[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/travel/record',
|
||||
url: '/home-api/travel/record',
|
||||
method: 'get',
|
||||
params: { startDate, endDate }
|
||||
})
|
||||
|
||||
export const queryTravelCategoryApi = (): Promise<string[]> =>
|
||||
cloudService({
|
||||
url: '/home-service/travel/category',
|
||||
url: '/home-api/travel/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryTravelStatsApi = (): Promise<ITravelStats> =>
|
||||
cloudService({
|
||||
url: '/home-service/travel/stats',
|
||||
url: '/home-api/travel/stats',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import { cloudService } from './index'
|
||||
|
||||
export const getAllTravelRecord = (): any =>
|
||||
cloudService({
|
||||
url: '/travelRecord/getAllTravelRecord',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const getAllTravelRecordByPage = (currentPage: number, pageSize: number): any =>
|
||||
cloudService({
|
||||
url: '/travelRecord/getAllTravelRecordByPage',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize }
|
||||
})
|
||||
|
||||
export const addTravelRecord = (travelJournal): any =>
|
||||
cloudService({
|
||||
url: '/travelRecord/addTravelRecord',
|
||||
method: 'post',
|
||||
data: travelJournal
|
||||
})
|
||||
|
||||
export const addTravelRecordImage = (imageList, date, place): any =>
|
||||
cloudService({
|
||||
url: '/travelRecord/addTravelRecordImage',
|
||||
method: 'post',
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
params: { date, place },
|
||||
data: imageList
|
||||
})
|
||||
|
||||
@@ -3,13 +3,13 @@ import { IUser } from '@/types/auth.ts'
|
||||
|
||||
export const queryUserApi = (id: number): Promise<IUser> =>
|
||||
cloudService({
|
||||
url: `/home-service/user/${id}`,
|
||||
url: `/home-api/user/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const updateUserApi = (id: number, user: IUser): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/home-service/user/${id}`,
|
||||
url: `/home-api/user/${id}`,
|
||||
method: 'put',
|
||||
data: user
|
||||
})
|
||||
|
||||
BIN
src/assets/font/custom.woff2
Normal file
BIN
src/assets/font/custom.woff2
Normal file
Binary file not shown.
Binary file not shown.
@@ -29,8 +29,7 @@ import { defineProps, PropType } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAnniversaryStore } from '@/store/anniversary.ts'
|
||||
import { IAnniversary } from '@/types/anniversary.ts'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
import { getAnniversaryRemainDays } from '@/utils/home/anniversaryUtil'
|
||||
import { getAnniversaryRemainDays } from '@/utils/home/anniversaryUtil.ts'
|
||||
|
||||
const router = useRouter()
|
||||
const anniversaryStore = useAnniversaryStore()
|
||||
@@ -45,10 +44,10 @@ const props = defineProps({
|
||||
const selectDateCardClick = async () => {
|
||||
anniversaryStore.anniversaryApiType = 'UPDATE'
|
||||
|
||||
if (isMobile() && props.dateItem?.category !== '节假日') {
|
||||
if (props.dateItem?.category !== '节假日') {
|
||||
anniversaryStore.currentAnniversary = props.dateItem as IAnniversary
|
||||
const { id } = anniversaryStore.currentAnniversary
|
||||
await router.push({ name: 'MobileHomeAnniversaryDetailId', params: { id } })
|
||||
await router.push({ name: 'AnniversaryDetailId', params: { id } })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="isMobile()" class="mobile-common-query card-item">
|
||||
<div class="mobile-common-query card-item">
|
||||
<div class="query-item">
|
||||
<span>分类:</span>
|
||||
<el-segmented v-model="anniversaryStore.queryInfo.category"
|
||||
@@ -7,27 +7,11 @@
|
||||
@change="anniversaryStore.queryAnniversaryList()"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="common-query">
|
||||
<el-select v-model="anniversaryStore.queryInfo.category"
|
||||
placeholder="请选择纪念日类别" clearable
|
||||
@change="anniversaryStore.queryAnniversaryList()"
|
||||
style="width: 180px">
|
||||
<el-option
|
||||
v-for="(item, index) in queryCategoryList"
|
||||
:key="index" :label="item.label" :value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-button :icon="Refresh" circle @click="refreshClick"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useAnniversaryStore } from '@/store/anniversary.ts'
|
||||
import { Refresh } from '@element-plus/icons-vue'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
import { ICategory } from '@/types'
|
||||
|
||||
const anniversaryStore = useAnniversaryStore()
|
||||
@@ -39,11 +23,6 @@ onMounted(async () => {
|
||||
initCategoryList()
|
||||
})
|
||||
|
||||
const refreshClick = async () => {
|
||||
anniversaryStore.queryInfo.category = ''
|
||||
await anniversaryStore.queryAnniversaryList()
|
||||
}
|
||||
|
||||
const initCategoryList = () => {
|
||||
queryCategoryList.value = []
|
||||
queryCategoryList.value.push({
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, PropType } from 'vue'
|
||||
import { IAnniversaryCategory } from '@/types/anniversary'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
import { useAnniversaryStore } from '@/store/anniversary'
|
||||
import { IAnniversaryCategory } from '@/types/anniversary.ts'
|
||||
import { useAnniversaryStore } from '@/store/anniversary.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const props = defineProps({
|
||||
categoryItem: {
|
||||
@@ -29,9 +29,11 @@ const router = useRouter()
|
||||
const anniversaryStore = useAnniversaryStore()
|
||||
|
||||
const selectCategoryClick = () => {
|
||||
if (isMobile()) {
|
||||
if (props.count) {
|
||||
anniversaryStore.queryInfo.category = props.categoryItem?.name as string
|
||||
router.push({ name: 'MobileHomeAnniversaryList' })
|
||||
router.push({ name: 'AnniversaryList' })
|
||||
} else {
|
||||
ElMessage.info('暂无纪念日')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -33,11 +33,9 @@
|
||||
<script setup lang="ts">
|
||||
import { SvgIcon } from 'vue3-common'
|
||||
import { defineProps, PropType } from 'vue'
|
||||
import { IAsset, IAssetItem } from '@/types/asset'
|
||||
import { IAsset, IAssetItem } from '@/types/asset.ts'
|
||||
import { formatAmount } from 'vue3-common/utils/numberUtil'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { useAssetStore } from '@/store/asset'
|
||||
import { useAssetStore } from '@/store/asset.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -62,15 +60,7 @@ const editClick = async (asset: IAssetItem) => {
|
||||
assetStore.assetApiType = 'UPDATE'
|
||||
assetStore.currentAssetRecord = assetStore.assetRecordList.find((item) => item.id === asset.id)
|
||||
|
||||
if (isMobile()) {
|
||||
await router.push({ name: 'MobileHomeAssetDetailId', params: { id: asset.id } })
|
||||
} else {
|
||||
assetStore.assetDialog = {
|
||||
title: '编辑资产',
|
||||
visible: true,
|
||||
data: deepCopyObject(assetStore.currentAssetRecord)
|
||||
}
|
||||
}
|
||||
await router.push({ name: 'AssetDetailId', params: { id: asset.id } })
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="isMobile()" class="mobile-common-query card-item">
|
||||
<div class="mobile-common-query card-item">
|
||||
<div class="query-item">
|
||||
<span>分类:</span>
|
||||
<el-segmented v-model="assetStore.queryInfo.category"
|
||||
@@ -7,27 +7,11 @@
|
||||
@change="assetStore.refreshInfo()"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="common-query">
|
||||
<el-select v-model="assetStore.queryInfo.category"
|
||||
placeholder="请选择纪念日类别" clearable
|
||||
@change="assetStore.refreshInfo()"
|
||||
style="width: 180px">
|
||||
<el-option
|
||||
v-for="(item, index) in queryCategoryList"
|
||||
:key="index" :label="item.label" :value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-button :icon="Refresh" circle @click="refreshClick"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useAssetStore } from '@/store/asset.ts'
|
||||
import { Refresh } from '@element-plus/icons-vue'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
import { ICategory } from '@/types'
|
||||
|
||||
const assetStore = useAssetStore()
|
||||
@@ -39,11 +23,6 @@ onMounted(async () => {
|
||||
initCategoryList()
|
||||
})
|
||||
|
||||
const refreshClick = async () => {
|
||||
assetStore.queryInfo.category = ''
|
||||
await assetStore.queryAssetList()
|
||||
}
|
||||
|
||||
const initCategoryList = () => {
|
||||
queryCategoryList.value = []
|
||||
queryCategoryList.value.push({
|
||||
97
src/components/Award/AwardCard.vue
Normal file
97
src/components/Award/AwardCard.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div class="life-record-card card-item">
|
||||
<el-image v-if="props.item?.imageList.length > 0"
|
||||
:src="`${props.item?.imageList[0]}${ThumbImageQuery}`"
|
||||
fit="contain" alt="暂无图片" @click="viewImageClick">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<span>暂无图片</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
|
||||
<el-empty v-else description="暂无图片" />
|
||||
|
||||
<van-swipe-cell>
|
||||
<div class="record-info" @click="editClick()">
|
||||
<div class="top-container">
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<span class="title">{{ props.item.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-container">
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-location-dot" style="color: #6A5ACD"></i>
|
||||
{{ props.item.location }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-flag"></i>
|
||||
{{ props.item.owner }}
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<i class="fa-regular fa-calendar-check"></i>
|
||||
{{ props.item.date }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #right>
|
||||
<van-button square type="primary" text="编辑" style="height: 100%;"
|
||||
@click="editClick"/>
|
||||
<van-button square type="danger" text="删除" style="height: 100%;"
|
||||
@click="deleteClick()"/>
|
||||
</template>
|
||||
</van-swipe-cell>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAwardStore } from '@/store/award.ts'
|
||||
import { defineProps, PropType } from 'vue'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { RawImageQuery, ThumbImageQuery } from '@/utils'
|
||||
import { showImagePreview } from 'vant'
|
||||
import { IAward } from '@/types/award.ts'
|
||||
|
||||
const awardStore = useAwardStore()
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
required: true,
|
||||
type: Object as PropType<IAward>
|
||||
}
|
||||
})
|
||||
|
||||
const viewImageClick = () => {
|
||||
const imageList = props.item.imageList.map((item) => `${item}${RawImageQuery}`)
|
||||
showImagePreview({ images: imageList, closeable: true })
|
||||
}
|
||||
|
||||
const editClick = async () => {
|
||||
const id = props.item?.id
|
||||
awardStore.awardApiType = 'UPDATE'
|
||||
|
||||
awardStore.currentAward = props.item as IAward
|
||||
await router.push({ name: 'AwardDetailId', params: { id } })
|
||||
}
|
||||
|
||||
const deleteClick = () => {
|
||||
awardStore.awardApiType = 'DELETE'
|
||||
commonElMessageBox(`请确认是否删除该记录: ${props.item?.name}?`).then(() => {
|
||||
awardStore.handleAwardApi(props.item as IAward)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/home/life.record.module";
|
||||
</style>
|
||||
37
src/components/Award/AwardQuery.vue
Normal file
37
src/components/Award/AwardQuery.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="mobile-common-query card-item">
|
||||
<div class="query-item">
|
||||
<span>类型:</span>
|
||||
<el-segmented v-model="awardStore.queryInfo.type"
|
||||
:options="queryTypeList"
|
||||
@change="awardStore.queryAwardList()"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAwardStore } from '@/store/award.ts'
|
||||
|
||||
const awardStore = useAwardStore()
|
||||
|
||||
const queryTypeList = [
|
||||
{
|
||||
label: '全部',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
label: '获奖',
|
||||
value: '获奖'
|
||||
},
|
||||
{
|
||||
label: '技能',
|
||||
value: '技能'
|
||||
}, {
|
||||
label: '身份',
|
||||
value: '身份'
|
||||
}, {
|
||||
label: '财产',
|
||||
value: '财产'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
@@ -12,13 +12,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BillDailyItem from '@/components/Home/Bill/BillDailyItem.vue'
|
||||
import BillDailyItem from '@/components/Bill/BillDailyItem.vue'
|
||||
import { reactive, watch, ref, onMounted } from 'vue'
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
import { formatDate } from 'vue3-common/utils/dateUtil'
|
||||
import { CalendarDay, Page } from 'v-calendar/dist/types/src/utils/page'
|
||||
import { getCalendarDateList } from '@/utils/home/billUtil.ts'
|
||||
import { useAppStore } from '@/store/app'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
|
||||
const calendarRef = ref()
|
||||
const billStore = useBillStore()
|
||||
@@ -67,7 +67,7 @@ const getCalendarAttrDates = () => {
|
||||
})
|
||||
dailyInfo.attrs.push({
|
||||
dot: 'red',
|
||||
dates: getCalendarDateList(billStore.billRecordList, 'expensive')
|
||||
dates: getCalendarDateList(billStore.billRecordList, 'expense')
|
||||
})
|
||||
dailyInfo.attrs.push({
|
||||
dot: 'green',
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="bill-chart"
|
||||
<div class="bill-chart common-chart"
|
||||
v-loading="billStore.isLoading"
|
||||
element-loading-text="正在加载中...">
|
||||
<div class="chart-container card-item">
|
||||
@@ -8,19 +8,22 @@
|
||||
</div>
|
||||
<div class="chart" ref="billDailyChartRef"/>
|
||||
</div>
|
||||
|
||||
<div class="chart-container card-item">
|
||||
<div class="content">
|
||||
<span class="title">📊类别统计</span>
|
||||
</div>
|
||||
<div class="chart" ref="billCategoryChartRef"/>
|
||||
</div>
|
||||
|
||||
<div class="chart-container card-item">
|
||||
<div class="content">
|
||||
<span class="title">📊账本统计</span>
|
||||
</div>
|
||||
<div class="chart" ref="billBookChartRef"/>
|
||||
</div>
|
||||
<div v-if="isMobile()" class="chart-container card-item">
|
||||
|
||||
<div class="chart-container card-item">
|
||||
<div class="content">
|
||||
<span class="title">📊排行榜</span>
|
||||
</div>
|
||||
@@ -28,24 +31,17 @@
|
||||
<bill-rank />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="chart-container card-item">
|
||||
<div class="content">
|
||||
<span class="title">📊排行榜</span>
|
||||
</div>
|
||||
<div class="chart" ref="billRankChartRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BillRank from '@/components/Home/Bill/BillRank.vue'
|
||||
import BillRank from '@/components/Bill/BillRank.vue'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import { lineChartOptions, barChartOptions, pieChartOptions } from 'vue3-common/utils/eChartsUtil'
|
||||
import { useBillStore } from '@/store/bill'
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
import type { IStatsChart } from 'vue3-common/types'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
import { formatDate } from 'vue3-common/utils/dateUtil'
|
||||
|
||||
const billStore = useBillStore()
|
||||
const appStore = useAppStore()
|
||||
@@ -53,12 +49,10 @@ const appStore = useAppStore()
|
||||
const billDailyChartRef = ref<HTMLElement>()
|
||||
const billBookChartRef = ref<HTMLElement>()
|
||||
const billCategoryChartRef = ref<HTMLElement>()
|
||||
const billRankChartRef = ref<HTMLElement>()
|
||||
|
||||
let billDailyChart: echarts.ECharts
|
||||
let billBookChart: echarts.ECharts
|
||||
let billCategoryChart: echarts.ECharts
|
||||
let billRankChart: echarts.ECharts
|
||||
|
||||
watch(() => billStore.isRefresh, () => {
|
||||
updateChart()
|
||||
@@ -68,29 +62,29 @@ onMounted(() => {
|
||||
billDailyChart = echarts.init(billDailyChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
||||
billBookChart = echarts.init(billBookChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
||||
billCategoryChart = echarts.init(billCategoryChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
||||
|
||||
if (!isMobile()) {
|
||||
billRankChart = echarts.init(billRankChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
||||
}
|
||||
})
|
||||
|
||||
const updateChart = () => {
|
||||
const MAX_CATEGORY_COUNT = 5
|
||||
const MAX_RANK_COUNT = 10
|
||||
|
||||
// 收支统计图
|
||||
const dailyXAxis = billStore.billDateStatsList.map((item) => item.name)
|
||||
const dailyXAxis = billStore.billDateStatsList.map((item) => {
|
||||
return formatDate(item.name, 'MM-DD')
|
||||
})
|
||||
const dailyYAxis = billStore.billDateStatsList.map((item) => item.value)
|
||||
billDailyChart.setOption(lineChartOptions('日期', dailyXAxis, '金额(元)', dailyYAxis))
|
||||
billDailyChart.setOption({
|
||||
series: [{
|
||||
itemStyle: {
|
||||
color: billStore.billType === 'expensive' ? '#CA6C65' : '#6FBB69'
|
||||
color: billStore.billType === 'expense' ? '#CA6C65' : '#6FBB69'
|
||||
},
|
||||
markPoint: {
|
||||
label: {
|
||||
color: '#FFFFFF'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
show: false
|
||||
}
|
||||
}]
|
||||
})
|
||||
@@ -102,7 +96,7 @@ const updateChart = () => {
|
||||
billBookChart.setOption({
|
||||
series: [{
|
||||
itemStyle: {
|
||||
color: billStore.billType === 'expensive' ? '#CA6C65' : '#6FBB69'
|
||||
color: billStore.billType === 'expense' ? '#CA6C65' : '#6FBB69'
|
||||
},
|
||||
markPoint: {
|
||||
label: {
|
||||
@@ -116,7 +110,6 @@ const updateChart = () => {
|
||||
const billCategoryList = billStore.billCategoryStatsList.slice(0, MAX_CATEGORY_COUNT)
|
||||
billCategoryChart.setOption(pieChartOptions('rank', '元', billCategoryList))
|
||||
|
||||
if (isMobile()) {
|
||||
billCategoryChart.setOption({
|
||||
series: [{
|
||||
radius: ['20%', '50%'],
|
||||
@@ -126,19 +119,4 @@ const updateChart = () => {
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
// 排行榜统计图
|
||||
const billRankList: IStatsChart[] = []
|
||||
const resultList = billStore.billRecordList.filter((item) => item.type === billStore.billType)
|
||||
resultList.sort((a, b) => b.amount - a.amount).forEach((item) => {
|
||||
billRankList.push({
|
||||
name: item.content,
|
||||
value: item.amount
|
||||
})
|
||||
})
|
||||
|
||||
if (!isMobile()) {
|
||||
billRankChart.setOption(pieChartOptions('rank', '元', billRankList.slice(0, MAX_RANK_COUNT)))
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -5,7 +5,7 @@
|
||||
<daily-summary :date="dailyItemInfo.date">
|
||||
<template #extra>
|
||||
<span>收入:{{ formatAmount(dailyItemInfo.totalIncome, true) }}</span>
|
||||
<span>支出:{{ formatAmount(dailyItemInfo.totalExpensive, true) }}</span>
|
||||
<span>支出:{{ formatAmount(dailyItemInfo.totalExpense, true) }}</span>
|
||||
</template>
|
||||
</daily-summary>
|
||||
|
||||
@@ -36,20 +36,16 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import DailySummary from '@/components/Home/DailySummary.vue'
|
||||
import DailyCard from '@/components/Home/DailyCard.vue'
|
||||
import DailySummary from '@/components/DailySummary.vue'
|
||||
import DailyCard from '@/components/DailyCard.vue'
|
||||
import { defineProps, onMounted, reactive, watch } from 'vue'
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { formatChineseDate } from 'vue3-common/utils/dateUtil'
|
||||
import { IBillRecord } from '@/types/bill.ts'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { formatAmount } from 'vue3-common/utils/numberUtil'
|
||||
import { getCalendarDailyCount, getCategoryByName } from '@/utils/home/billUtil.ts'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
|
||||
const billStore = useBillStore()
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
date: {
|
||||
@@ -72,7 +68,7 @@ onMounted(() => {
|
||||
|
||||
const dailyItemInfo = reactive({
|
||||
date: '',
|
||||
totalExpensive: 0,
|
||||
totalExpense: 0,
|
||||
totalIncome: 0,
|
||||
itemList: [] as IBillRecord[]
|
||||
})
|
||||
@@ -88,7 +84,7 @@ const getBillDailyByDate = (date: string) => {
|
||||
const calendarDaily = getCalendarDailyCount(billStore.billRecordList, date)
|
||||
dailyItemInfo.itemList = calendarDaily.dailyRecordList
|
||||
dailyItemInfo.totalIncome = calendarDaily.totalIncome
|
||||
dailyItemInfo.totalExpensive = calendarDaily.totalExpensive
|
||||
dailyItemInfo.totalExpense = calendarDaily.totalExpense
|
||||
} else {
|
||||
dailyItemInfo.itemList = []
|
||||
}
|
||||
@@ -101,19 +97,7 @@ const getBillDailyByDate = (date: string) => {
|
||||
const selectBillRecordClick = async (billRecord: IBillRecord) => {
|
||||
await billStore.queryBillRecord(billRecord.id as number)
|
||||
billStore.billApiType = 'UPDATE'
|
||||
|
||||
if (isMobile()) {
|
||||
await router.push({
|
||||
name: 'MobileHomeBillDetailId',
|
||||
params: { id: billStore.currentBillRecord.id }
|
||||
})
|
||||
} else {
|
||||
billStore.billDialog = {
|
||||
title: '编辑账单',
|
||||
visible: true,
|
||||
data: deepCopyObject(billStore.currentBillRecord)
|
||||
}
|
||||
}
|
||||
billStore.billDrawer = true
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BillDailyItem from '@/components/Home/Bill/BillDailyItem.vue'
|
||||
import BillDailyItem from '@/components/Bill/BillDailyItem.vue'
|
||||
import { reactive, watch } from 'vue'
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
|
||||
263
src/components/Bill/BillDrawer.vue
Normal file
263
src/components/Bill/BillDrawer.vue
Normal file
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<el-drawer v-model="billStore.billDrawer" destroy-on-close
|
||||
:with-header="false" direction="btt" size="95%">
|
||||
<div class="common-mobile-view bill-detail">
|
||||
<el-form ref="formRef" :model="billStore.currentBillRecord"
|
||||
:rules="rules" label-position="top" label-width="80px"
|
||||
class="form-item bill-form">
|
||||
<div class="item-list">
|
||||
<el-select v-model="billStore.currentBillRecord.bookName"
|
||||
@change="changeBillBookNameEvent" style="width: 100px">
|
||||
<el-option
|
||||
v-for="item in billStore.billBookList"
|
||||
:key="item.id" :label="item.name" :value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-select v-model="billStore.currentBillRecord.type"
|
||||
@change="changeBillCategoryEvent" style="width: 100px">
|
||||
<el-option
|
||||
v-for="(item, index) in billInfo.billTypeList"
|
||||
:key="index" :label="getBillTypeName(item)" :value="item"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-select v-model="billStore.currentBillRecord.payAccount"
|
||||
@change="changeBillCategoryEvent" style="width: 100px">
|
||||
<el-option
|
||||
v-for="item in billStore.billPayList"
|
||||
:key="item.id" :label="item.name" :value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<el-radio-group v-model="billStore.currentBillRecord.category" class="bill-category-group">
|
||||
<el-radio-button v-for="(item, index) in billInfo.billCategoryList"
|
||||
:value="item.name" :key="index">
|
||||
<template #default>
|
||||
<i :class="item.icon"/>
|
||||
<span style="margin-left: 5px;">{{ item.name }}</span>
|
||||
</template>
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
|
||||
<div class="bill-gap"></div>
|
||||
|
||||
<div class="item-list">
|
||||
<el-date-picker
|
||||
v-model="billStore.currentBillRecord.date"
|
||||
type="date" :editable="false" placeholder="请选择账单时间"
|
||||
value-format="YYYY-MM-DD"/>
|
||||
|
||||
<el-input v-model="billStore.currentBillRecord.location" autocomplete="off"
|
||||
placeholder="请输入账单地点" clearable
|
||||
show-word-limit maxlength="10">
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon"><location/></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<el-input v-model="billStore.currentBillRecord.content" autocomplete="off"
|
||||
placeholder="请输入账单内容" clearable
|
||||
show-word-limit maxlength="10">
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon"><document/></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-input v-model="billStore.currentBillRecord.remark" type="textarea"
|
||||
placeholder="请输入账单备注" clearable
|
||||
:rows="3" show-word-limit maxlength="50">
|
||||
</el-input>
|
||||
|
||||
<number-input v-model:amount="billInfo.amountStr" class="amount-input" />
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div style="flex: auto">
|
||||
<el-button type="primary" @click="confirmClick">确认</el-button>
|
||||
<el-button v-if="billStore.billApiType === 'UPDATE'"
|
||||
type="danger" @click="deleteClick">删除</el-button>
|
||||
<el-button type="info" @click="cancelClick">取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
import { Location, Document } from '@element-plus/icons-vue'
|
||||
import { ElMessage, FormRules, UploadUserFile } from 'element-plus'
|
||||
import { billRecordRules } from '@/utils/element/elRules.ts'
|
||||
import { nextTick, reactive, ref, watch } from 'vue'
|
||||
import { IBillCategory } from '@/types/bill.ts'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
import NumberInput from '@/components/NumberInput.vue'
|
||||
|
||||
const formRef = ref()
|
||||
const rules = reactive<FormRules>(billRecordRules)
|
||||
const billStore = useBillStore()
|
||||
const imageFileList = ref<UploadUserFile[]>([])
|
||||
|
||||
const billInfo = reactive({
|
||||
billTypeList: [] as string[],
|
||||
billCategoryList: [] as IBillCategory[],
|
||||
amountStr: ''
|
||||
})
|
||||
|
||||
watch(() => billStore.billDrawer, async (value) => {
|
||||
if (value) {
|
||||
await initBillRecord()
|
||||
initImageFileList()
|
||||
|
||||
billInfo.amountStr = billStore.currentBillRecord.amount.toString()
|
||||
}
|
||||
})
|
||||
|
||||
const initBillRecord = async () => {
|
||||
// 如果是新增账单 默认选择第一个账本
|
||||
if (billStore.billApiType !== 'UPDATE') {
|
||||
billStore.currentBillRecord.bookName = billStore.billBookList[0].name
|
||||
}
|
||||
getBillTypeByBookName(billStore.currentBillRecord.bookName)
|
||||
|
||||
// 如果是新增账单 默认选择一个类别
|
||||
if (billStore.billApiType !== 'UPDATE') {
|
||||
billStore.currentBillRecord.type = billInfo.billTypeList[0]
|
||||
}
|
||||
getBillCategory()
|
||||
|
||||
// 如果是新增账单 默认选择一个分类
|
||||
if (billStore.billApiType !== 'UPDATE') {
|
||||
billStore.currentBillRecord.category = billInfo.billCategoryList[0].name
|
||||
billStore.currentBillRecord.payAccount = billStore.billPayList[0].name
|
||||
}
|
||||
|
||||
await nextTick(() => {
|
||||
formRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
const initImageFileList = () => {
|
||||
imageFileList.value = []
|
||||
billStore.currentBillRecord.imageList.forEach((image) => {
|
||||
imageFileList.value.push({
|
||||
name: 'image',
|
||||
url: image
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取账单类型名称
|
||||
* @param type 账单类型
|
||||
*/
|
||||
const getBillTypeName = (type: string) => {
|
||||
return type === 'expense' ? '支出' : '收入'
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择账本事件
|
||||
* @param value 账本名称
|
||||
*/
|
||||
const changeBillBookNameEvent = (value: string) => {
|
||||
getBillTypeByBookName(value)
|
||||
billStore.currentBillRecord.type = billInfo.billTypeList[0]
|
||||
getBillCategory()
|
||||
billStore.currentBillRecord.category = billInfo.billCategoryList[0].name
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择账单类别事件
|
||||
*/
|
||||
const changeBillCategoryEvent = () => {
|
||||
getBillCategory()
|
||||
billStore.currentBillRecord.category = billInfo.billCategoryList[0].name
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过账本获取账单类型
|
||||
* @param bookName 账本
|
||||
*/
|
||||
const getBillTypeByBookName = (bookName: string) => {
|
||||
billInfo.billTypeList = []
|
||||
billStore.billCategoryList.forEach((item) => {
|
||||
if (item.bookName === bookName && !billInfo.billTypeList.includes(item.type)) {
|
||||
billInfo.billTypeList.push(item.type)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取账单类别
|
||||
*/
|
||||
const getBillCategory = () => {
|
||||
billInfo.billCategoryList = billStore.billCategoryList.filter((value) => {
|
||||
return value.bookName === billStore.currentBillRecord.bookName
|
||||
&& value.type === billStore.currentBillRecord.type
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击确认按钮
|
||||
*/
|
||||
const confirmClick = () => {
|
||||
if (billStore.currentBillRecord.content.trim()) {
|
||||
formRef.value.validate().then(async () => {
|
||||
billStore.currentBillRecord.amount = Number(billInfo.amountStr)
|
||||
await billStore.handleBillApi(billStore.currentBillRecord)
|
||||
billStore.billDrawer = false
|
||||
})
|
||||
} else {
|
||||
ElMessage.error('请输入账单内容')
|
||||
}
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
billStore.billDrawer = false
|
||||
}
|
||||
|
||||
const deleteClick = () => {
|
||||
commonElMessageBox('是否确认删除该账单内容?').then(async () => {
|
||||
billStore.billApiType = 'DELETE'
|
||||
await billStore.handleBillApi(billStore.currentBillRecord)
|
||||
billStore.billDrawer = false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.bill-detail {
|
||||
.bill-form {
|
||||
flex-grow: 1;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
|
||||
.item-list {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.bill-category-group {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
|
||||
.el-radio-button {
|
||||
.el-radio-button__inner {
|
||||
padding: 8px 10px;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bill-gap {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="common-query">
|
||||
<el-select v-model="billStore.billQueryForm.billBook"
|
||||
@change="billStore.refreshInfo()" style="width: 120px">
|
||||
@change="billStore.refreshInfo(isStats)">
|
||||
<el-option
|
||||
v-for="(item, index) in billQuery.billBookList"
|
||||
:key="index" :label="item.label" :value="item.name"
|
||||
@@ -9,34 +9,32 @@
|
||||
</el-select>
|
||||
|
||||
<el-select v-model="billStore.billDateType"
|
||||
@change="billStore.refreshInfo()"
|
||||
style="width: 120px;align-self: center;">
|
||||
@change="billStore.refreshInfo(isStats)">
|
||||
<el-option v-for="(item, index) in dateTypeOptions" :key="index"
|
||||
:label="item.label" :value="item.value"/>
|
||||
</el-select>
|
||||
|
||||
<el-switch
|
||||
v-model="billStore.billType"
|
||||
inline-prompt
|
||||
active-value="income" inactive-value="expensive"
|
||||
active-text="收入账单" inactive-text="支出账单"
|
||||
@change="billStore.refreshInfo()"
|
||||
style="--el-switch-on-color: #6FBB69; --el-switch-off-color: #CA6C65;"
|
||||
/>
|
||||
<el-select v-if="isStats" v-model="billStore.billType"
|
||||
@change="billStore.refreshInfo(isStats)">
|
||||
<el-option v-for="(item, index) in billTypeOptions" :key="index"
|
||||
:label="item.label" :value="item.value"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { IBillBook } from '@/types/bill.ts'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const billStore = useBillStore()
|
||||
const route = useRoute()
|
||||
|
||||
const isStats = computed(() => route.path.includes('chart'))
|
||||
|
||||
onMounted(async () => {
|
||||
await billStore.initBillInfo()
|
||||
|
||||
billQuery.billBookList = deepCopyObject(billStore.billBookList)
|
||||
billQuery.billBookList.push({
|
||||
color: '',
|
||||
@@ -56,6 +54,15 @@ const dateTypeOptions = [{
|
||||
value: 'year'
|
||||
}]
|
||||
|
||||
const billTypeOptions = [{
|
||||
label: '收入',
|
||||
value: 'income'
|
||||
},
|
||||
{
|
||||
label: '支出',
|
||||
value: 'expense'
|
||||
}]
|
||||
|
||||
const billQuery = reactive({
|
||||
query: '',
|
||||
billBookList: [] as IBillBook[]
|
||||
@@ -3,14 +3,15 @@
|
||||
:key="index" class="rank-item">
|
||||
<span class="rank-index">{{ index+1 }}.</span>
|
||||
<span class="rank-content">{{ item.content }}</span>
|
||||
<span class="rank-amount">¥{{ item.amount }}</span>
|
||||
<span class="rank-amount">¥{{ formatAmount(item.amount) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBillStore } from '@/store/bill'
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
import { getBillSortByAmount } from '@/utils/home/billUtil.ts'
|
||||
import { computed } from 'vue'
|
||||
import { formatAmount } from 'vue3-common/utils/numberUtil'
|
||||
|
||||
const billStore = useBillStore()
|
||||
|
||||
34
src/components/Bill/BillSearch.vue
Normal file
34
src/components/Bill/BillSearch.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="common-query">
|
||||
<el-form :model="billStore.billSearchForm">
|
||||
<el-form-item label="账单内容">
|
||||
<el-input v-model="billStore.billSearchForm.content"
|
||||
@input="billStore.searchInfo()"
|
||||
placeholder="请输入账单内容" clearable/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单类别">
|
||||
<el-input v-model="billStore.billSearchForm.category"
|
||||
@input="billStore.searchInfo()"
|
||||
placeholder="请输入账单类别" clearable/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单地址">
|
||||
<el-input v-model="billStore.billSearchForm.location"
|
||||
@input="billStore.searchInfo()"
|
||||
placeholder="请输入账单地址" clearable/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
|
||||
const billStore = useBillStore()
|
||||
|
||||
onMounted(async () => {
|
||||
await billStore.searchInfo()
|
||||
})
|
||||
</script>
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="common-statistics">
|
||||
<stats-card
|
||||
title="当前支出" color="#CA6C65" unit="元" icon="fa-solid fa-sack-xmark"
|
||||
:value="formatAmount(billStats.expensive)" />
|
||||
:value="formatAmount(billStats.expense)" />
|
||||
|
||||
<stats-card
|
||||
title="当前收入" color="#6FBB69" unit="元" icon="fa-solid fa-sack-dollar"
|
||||
@@ -19,11 +19,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import StatsCard from '@/components/Home/StatsCard.vue'
|
||||
import { useBillStore } from '@/store/bill'
|
||||
import StatsCard from '@/components/StatsCard.vue'
|
||||
import { useBillStore } from '@/store/bill.ts'
|
||||
import { ref, watch } from 'vue'
|
||||
import { getBillSummaryStats } from '@/utils/home/billUtil'
|
||||
import { IBillSummaryStats } from '@/types/bill'
|
||||
import { getBillSummaryStats } from '@/utils/home/billUtil.ts'
|
||||
import { IBillSummaryStats } from '@/types/bill.ts'
|
||||
import { formatAmount } from 'vue3-common/utils/numberUtil'
|
||||
|
||||
const billStore = useBillStore()
|
||||
@@ -34,7 +34,7 @@ watch(() => billStore.isRefresh, () => {
|
||||
|
||||
const billStats = ref<IBillSummaryStats>({
|
||||
balance: 0,
|
||||
expensive: 0,
|
||||
expense: 0,
|
||||
income: 0,
|
||||
rate: 0
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-archive blog-section">
|
||||
<div class="blog-archive blog-section card-item">
|
||||
<h4 class="module-title">文章归档</h4>
|
||||
|
||||
<el-date-picker
|
||||
@@ -53,10 +53,10 @@ const changeDateEvent = async (value: Date) => {
|
||||
*/
|
||||
const viewBlogClick = async (index: number) => {
|
||||
const blogId = blogStore.blogList[index].id
|
||||
await router.push({ name: 'BlogDetail', params: { id: blogId } })
|
||||
await router.push({ name: 'DetailId', params: { id: blogId } })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/blog/blog.archive.module.scss";
|
||||
@use "@/styles/blog/blog.archive.module";
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-category blog-section">
|
||||
<div class="blog-category blog-section card-item">
|
||||
<h4 class="module-title">文章分类</h4>
|
||||
|
||||
<span class="total">目前共计{{ blogStore.blogCategoryList.length }}个分类</span>
|
||||
@@ -31,10 +31,10 @@ onMounted(() => {
|
||||
* @param name 类别名称
|
||||
*/
|
||||
const viewBlogCategoryClick = async (name: string) => {
|
||||
await router.push({ name: 'BlogCategoryName', params: { name } })
|
||||
await router.push({ name: 'CategoryName', params: { name } })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/blog/blog.category.module.scss";
|
||||
@use "@/styles/blog/blog.category.module";
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-category-detail blog-section">
|
||||
<div class="blog-category-detail blog-section card-item">
|
||||
<span class="name">{{ route.params?.name }}</span>
|
||||
|
||||
<div class="category-detail-list">
|
||||
@@ -32,10 +32,10 @@ onMounted(async () => {
|
||||
|
||||
const viewBlogClick = async (index: number) => {
|
||||
const blogId = blogStore.blogList[index].id
|
||||
await router.push({ name: 'BlogDetailId', params: { id: blogId } })
|
||||
await router.push({ name: 'DetailId', params: { id: blogId } })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/blog/blog.category.detail.module.scss";
|
||||
@use "@/styles/blog/blog.category.detail.module";
|
||||
</style>
|
||||
|
||||
30
src/components/Blog/Comment/BlogComment.vue
Normal file
30
src/components/Blog/Comment/BlogComment.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="blog-comment card-item">
|
||||
<div class="comment-total">
|
||||
<span>共 {{ blogStore.blogNestedCommentList.length }} 条评论</span>
|
||||
</div>
|
||||
|
||||
<div class="comment-list">
|
||||
<blog-comment-item v-for="(item, index) in blogStore.blogNestedCommentList" :key="index"
|
||||
:comment="item.comment" :replyList="item.replies"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BlogCommentItem from '@/components/Comment/BlogCommentItem.vue'
|
||||
import { useBlogStore } from '@/store/blog.ts'
|
||||
|
||||
const blogStore = useBlogStore()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.blog-comment {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +1,14 @@
|
||||
<template>
|
||||
<div class="blog-detail blog-section" id="blog-section">
|
||||
<div class="blog-detail blog-section card-item" id="blog-section">
|
||||
<div class="blog-title">
|
||||
<span class="title">{{ blogStore.currentBlog.title }}</span>
|
||||
<blog-label :basic-blog="getBasicBlog(blogStore.currentBlog)"/>
|
||||
</div>
|
||||
|
||||
<div class="blog-md">
|
||||
<MdPreview editorId="blog-id" v-model="blogStore.currentBlog.content" />
|
||||
<div class="blog-md card-item">
|
||||
<MdPreview editorId="blog-id"
|
||||
v-model="blogStore.currentBlog.content"
|
||||
:theme="appStore.isDark ? 'dark' : 'light'"/>
|
||||
</div>
|
||||
|
||||
<div class="blog-copyright">
|
||||
@@ -28,28 +30,38 @@
|
||||
<div class="blog-ending">
|
||||
<span>-------------本文结束♥感谢您的阅读♥给个五星好评吧~~-------------</span>
|
||||
</div>
|
||||
|
||||
<blog-comment-edit :parent-id="0"/>
|
||||
|
||||
<blog-comment />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BlogLabel from '@/components/Blog/Content/BlogLabel.vue'
|
||||
import BlogLabel from '@/components/Content/BlogLabel.vue'
|
||||
import BlogCommentEdit from '@/components/Comment/BlogCommentEdit.vue'
|
||||
import BlogComment from '@/components/Comment/BlogComment.vue'
|
||||
import { MdPreview } from 'md-editor-v3'
|
||||
import 'md-editor-v3/lib/style.css'
|
||||
import { useBlogStore } from '@/store/blog.ts'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
import { getBasicBlog } from '@/utils/blog/blogUtil.ts'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const blogStore = useBlogStore()
|
||||
const appStore = useAppStore()
|
||||
const route = useRoute()
|
||||
|
||||
const currentUrl = new URL(window.location.href)
|
||||
|
||||
onMounted(async () => {
|
||||
await blogStore.queryBlogById(route.params.id as number)
|
||||
const blogId = route.params.id as number
|
||||
blogStore.currentBlogId = blogId
|
||||
await blogStore.queryBlogById(blogId)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/blog/blog.detail.module.scss";
|
||||
@use "@/styles/blog/blog.detail.module";
|
||||
</style>
|
||||
|
||||
@@ -88,5 +88,5 @@ const viewBlogCategoryClick = async () => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/blog/blog.label.module.scss";
|
||||
@use "@/styles/blog/blog.label.module";
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="blog-content-list blog-section">
|
||||
<div class="blog-content-list blog-section card-item">
|
||||
<div v-if="blogStore.blogList.length === 0"
|
||||
class="blog-content blog-content-empty" >
|
||||
</div>
|
||||
@@ -29,7 +29,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BlogLabel from '@/components/Blog/Content/BlogLabel.vue'
|
||||
import BlogLabel from '@/components/Content/BlogLabel.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { onMounted } from 'vue'
|
||||
import { useBlogStore } from '@/store/blog.ts'
|
||||
@@ -48,21 +48,19 @@ onMounted(async () => {
|
||||
*/
|
||||
const readBlogClick = async (index: number) => {
|
||||
const blogId = blogStore.blogList[index].id
|
||||
await router.push({ name: 'BlogDetailId', params: { id: blogId } })
|
||||
await router.push({ name: 'DetailId', params: { id: blogId } })
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击切换博客页数按钮
|
||||
* @param page 页码
|
||||
* @param pageSize 每页大小
|
||||
*/
|
||||
const changePageClick = async (page: number, pageSize: number) => {
|
||||
const changePageClick = async (page: number) => {
|
||||
blogStore.pageInfo.currentPage = page
|
||||
blogStore.pageInfo.pageSize = pageSize
|
||||
await blogStore.queryBlog()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/blog/blog.overview.module.scss";
|
||||
@use "@/styles/blog/blog.overview.module";
|
||||
</style>
|
||||
|
||||
108
src/components/Car/CarCard.vue
Normal file
108
src/components/Car/CarCard.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="life-record-card card-item">
|
||||
<el-image :src="`${props.carItem?.imageUrl}${ThumbImageQuery}`"
|
||||
fit="contain" alt="暂无图片" @click="viewImageClick">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<span>暂无图片</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
|
||||
<van-swipe-cell>
|
||||
<div class="record-info" @click="editClick()">
|
||||
<div class="top-container">
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<span class="title">{{ props.carItem.name }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-file-lines" style="color: #8e44ad"></i>
|
||||
{{ props.carItem.description }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tag type="primary" effect="dark">
|
||||
{{ props.carItem.type }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
<div class="bottom-container">
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-gauge" style="color: #3498db"></i>
|
||||
{{ props.carItem.mileage }} M
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-coins" style="color: #27ae60"></i>
|
||||
{{ props.carItem.cost }} 元
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-location-dot" style="color: #e67e22"></i>
|
||||
{{ props.carItem.location }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-calendar" style="color: #26a69a"></i>
|
||||
{{ props.carItem.date }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #right>
|
||||
<van-button square type="primary" text="编辑" style="height: 100%;"
|
||||
@click="editClick"/>
|
||||
<van-button square type="danger" text="删除" style="height: 100%;"
|
||||
@click="deleteClick()"/>
|
||||
</template>
|
||||
</van-swipe-cell>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCarStore } from '@/store/car.ts'
|
||||
import { defineProps, PropType } from 'vue'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ThumbImageQuery } from '@/utils'
|
||||
import { showImagePreview } from 'vant'
|
||||
import { ICarEvent } from '@/types/car.ts'
|
||||
|
||||
const carStore = useCarStore()
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
carItem: {
|
||||
required: true,
|
||||
type: Object as PropType<ICarEvent>
|
||||
}
|
||||
})
|
||||
|
||||
const viewImageClick = () => {
|
||||
showImagePreview({ images: [props.carItem?.imageUrl], closeable: true })
|
||||
}
|
||||
|
||||
const editClick = async () => {
|
||||
const id = props.carItem?.id
|
||||
carStore.carEventApiType = 'UPDATE'
|
||||
|
||||
carStore.currentCarEvent = props.carItem as ICarEvent
|
||||
await router.push({ name: 'CarDetailId', params: { id } })
|
||||
}
|
||||
|
||||
const deleteClick = () => {
|
||||
carStore.carEventApiType = 'DELETE'
|
||||
commonElMessageBox(`请确认是否删除该事件: ${props.carItem?.description}?`).then(() => {
|
||||
carStore.handleCarEventApi(props.carItem as ICarEvent)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/home/life.record.module";
|
||||
</style>
|
||||
33
src/components/Car/CarQuery.vue
Normal file
33
src/components/Car/CarQuery.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="mobile-common-query card-item">
|
||||
<div class="query-item">
|
||||
<span>类别:</span>
|
||||
<el-segmented v-model="carStore.queryInfo.type"
|
||||
:options="queryTypeList"
|
||||
@change="carStore.queryCarEventList()"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCarStore } from '@/store/car.ts'
|
||||
|
||||
const carStore = useCarStore()
|
||||
|
||||
const queryTypeList = [
|
||||
{
|
||||
label: '全部',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
label: '保养',
|
||||
value: '保养'
|
||||
}, {
|
||||
label: '事故',
|
||||
value: '事故'
|
||||
}, {
|
||||
label: '违章',
|
||||
value: '违章'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
@@ -16,5 +16,5 @@ const appStore = useAppStore()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/app.loading.module.scss";
|
||||
@use "@/styles/app.loading.module";
|
||||
</style>
|
||||
@@ -12,13 +12,22 @@
|
||||
{{ appStore.isDark ? '🌙' : '☀️' }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="setting-item">
|
||||
<span>我的</span>
|
||||
<el-button circle :icon="UserFilled" type="primary" @click="viewProfileClick"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
import { onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const router = useRouter()
|
||||
|
||||
onMounted(() => {
|
||||
appStore.themeColor = appStore.getThemeColor()
|
||||
@@ -27,6 +36,11 @@ onMounted(() => {
|
||||
const changeThemeColorEvent = (value: string) => {
|
||||
appStore.setThemeColor(value)
|
||||
}
|
||||
|
||||
const viewProfileClick = () => {
|
||||
router.push('/profile/index')
|
||||
appStore.isShowSetting = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -50,7 +50,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import WeatherIcon from '@/components/Mobile/WeatherIcon.vue'
|
||||
import WeatherIcon from '@/components/Common/WeatherIcon.vue'
|
||||
import { onMounted, onUnmounted, reactive } from 'vue'
|
||||
import axios from 'axios'
|
||||
import { Solar } from 'lunar-javascript'
|
||||
@@ -12,9 +12,8 @@
|
||||
<el-card class="record-card">
|
||||
<span class="record-content">完成人:{{ item.person }}</span>
|
||||
<el-image v-if="item.imageUrl"
|
||||
:src="serviceFileRootPath + item.imageUrl"
|
||||
:preview-src-list="[serviceFileRootPath + item.imageUrl]"
|
||||
fit="contain" alt="暂无图片" class="record-image"/>
|
||||
:src="`${item.imageUrl}${ThumbImageQuery}`" fit="cover" alt="暂无图片"
|
||||
@click="viewImageClick(item)" class="record-image"/>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
@@ -25,8 +24,14 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { serviceFileRootPath } from '@/utils'
|
||||
import { ThumbImageQuery } from '@/utils'
|
||||
import { SvgIcon } from 'vue3-common'
|
||||
import { IFoodRecord } from '@/types/food.ts'
|
||||
import { showImagePreview } from 'vant'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
const viewImageClick = (item: IFoodRecord) => {
|
||||
showImagePreview({ images: [item.imageUrl], closeable: true })
|
||||
}
|
||||
</script>
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="step-body">
|
||||
<span class="step-content">{{ item.content }}</span>
|
||||
<img v-if="item.imageUrl"
|
||||
:src="serviceFileRootPath + item.imageUrl" alt="暂无图片" class="step-image"/>
|
||||
:src="item.imageUrl" alt="暂无图片" class="step-image"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { serviceFileRootPath } from '@/utils'
|
||||
import { SvgIcon } from 'vue3-common'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
@@ -10,12 +10,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FoodDailyItem from '@/components/Home/Food/FoodDailyItem.vue'
|
||||
import FoodDailyItem from '@/components/Food/FoodDailyItem.vue'
|
||||
import { reactive, watch, ref, onMounted } from 'vue'
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { formatDate } from 'vue3-common/utils/dateUtil'
|
||||
import { CalendarDay } from 'v-calendar/dist/types/src/utils/page'
|
||||
import { useAppStore } from '@/store/app'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
|
||||
const calendarRef = ref()
|
||||
const foodStore = useFoodStore()
|
||||
115
src/components/Food/FoodCard.vue
Normal file
115
src/components/Food/FoodCard.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="life-record-card card-item">
|
||||
<el-image v-if="props.foodItem?.recordList.length > 0"
|
||||
:src="`${props.foodItem?.recordList[0].imageUrl}${ThumbImageQuery}`"
|
||||
fit="contain" alt="暂无成果" @click="viewImageClick">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<span>暂无图片</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
|
||||
<el-empty v-else description="暂无成果" />
|
||||
|
||||
<van-swipe-cell>
|
||||
<div class="record-info" @click="viewClick()">
|
||||
<div class="top-container">
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<span class="title">{{ props.foodItem.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-container">
|
||||
<div class="info-list">
|
||||
<div class="info-item category-item">
|
||||
<i class="fa-solid fa-utensils"></i>
|
||||
{{ props.foodItem.category }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="props.foodItem?.recordList.length > 0" class="info-list">
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-flag"></i>
|
||||
{{ props.foodItem.recordList[foodCardInfo.currentFoodIndex].person}}
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<i class="fa-regular fa-calendar-check"></i>
|
||||
{{ formatDate(props.foodItem.recordList[foodCardInfo.currentFoodIndex].date) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<span>暂无成果</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #right>
|
||||
<van-button square type="primary" text="编辑" style="height: 100%;"
|
||||
@click="editClick"/>
|
||||
<van-button square type="danger" text="删除" style="height: 100%;"
|
||||
@click="deleteClick()"/>
|
||||
</template>
|
||||
</van-swipe-cell>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { defineProps, onMounted, PropType, reactive } from 'vue'
|
||||
import { IFoodRecipe } from '@/types/food.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { formatDate } from 'vue3-common/utils/dateUtil'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
import { showImagePreview } from 'vant'
|
||||
import { RawImageQuery, ThumbImageQuery } from '@/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
const foodCardInfo = reactive({
|
||||
recommendRate: 0,
|
||||
currentFoodIndex: 0
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
foodItem: {
|
||||
required: true,
|
||||
type: Object as PropType<IFoodRecipe>
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
foodCardInfo.recommendRate = props.foodItem?.recommendRate as number
|
||||
})
|
||||
|
||||
const viewImageClick = () => {
|
||||
const imageList = props.foodItem?.recordList.map((item) => `${item.imageUrl}${RawImageQuery}`)
|
||||
showImagePreview({ images: imageList, closeable: true })
|
||||
}
|
||||
|
||||
const editClick = async () => {
|
||||
const id = props.foodItem?.id
|
||||
foodStore.foodRecipeApiType = 'UPDATE'
|
||||
await foodStore.queryFoodRecipe(id as number)
|
||||
await router.push({ name: 'FoodRecipeForm' })
|
||||
}
|
||||
|
||||
const viewClick = async () => {
|
||||
await router.push({ name: 'FoodDetailId', params: { id: props.foodItem?.id } })
|
||||
}
|
||||
|
||||
const deleteClick = () => {
|
||||
foodStore.foodRecipeApiType = 'DELETE'
|
||||
commonElMessageBox(`请确认是否删除该菜谱: ${props.foodItem?.name}?`).then(() => {
|
||||
foodStore.handleFoodRecipeApi(props.foodItem)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/home/life.record.module";
|
||||
</style>
|
||||
@@ -22,16 +22,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import DailySummary from '@/components/Home/DailySummary.vue'
|
||||
import DailyCard from '@/components/Home/DailyCard.vue'
|
||||
import DailySummary from '@/components/DailySummary.vue'
|
||||
import DailyCard from '@/components/DailyCard.vue'
|
||||
import { defineProps, onMounted, reactive, watch } from 'vue'
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
import { formatChineseDate } from 'vue3-common/utils/dateUtil'
|
||||
import { IFoodRecord } from '@/types/food.ts'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
const appStore = useAppStore()
|
||||
@@ -85,18 +83,10 @@ const getFoodDailyByDate = (date: string) => {
|
||||
*/
|
||||
const selectFoodRecordClick = async (foodRecord: IFoodRecord) => {
|
||||
foodStore.foodRecordApiType = 'UPDATE'
|
||||
|
||||
if (isMobile()) {
|
||||
appStore.isShowMobileBack = true
|
||||
foodStore.currentFoodRecord = foodRecord
|
||||
await router.push({ name: 'MobileHomeFoodRecordForm' })
|
||||
} else {
|
||||
foodStore.foodRecordDialog = {
|
||||
title: '编辑记录',
|
||||
visible: true,
|
||||
data: deepCopyObject(foodRecord)
|
||||
}
|
||||
}
|
||||
|
||||
appStore.isShowMobileBack = true
|
||||
await router.push({ name: 'FoodRecordForm' })
|
||||
}
|
||||
</script>
|
||||
|
||||
39
src/components/Food/FoodQuery.vue
Normal file
39
src/components/Food/FoodQuery.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div class="common-query">
|
||||
<el-select
|
||||
v-model="foodStore.queryRecipe.name"
|
||||
filterable clearable placeholder="请选择菜谱名称"
|
||||
style="width: 150px;"
|
||||
@change="changeFoodNameEvent">
|
||||
<el-option
|
||||
v-for="(item, index) in foodStore.foodNameList"
|
||||
:key="index" :label="item" :value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { onMounted } from 'vue'
|
||||
import { searchFoodRecipeApi } from '@/apis/food.ts'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
onMounted(async () => {
|
||||
await foodStore.queryFoodNameList()
|
||||
foodStore.queryRecipe.name = ''
|
||||
})
|
||||
|
||||
const changeFoodNameEvent = async (value: string) => {
|
||||
if (value) {
|
||||
const result = await searchFoodRecipeApi(value)
|
||||
foodStore.foodRecipeList = [result]
|
||||
} else {
|
||||
foodStore.pageInfo.currentPage = 1
|
||||
foodStore.pageInfo.pageSize = 3
|
||||
foodStore.foodRecipeList = []
|
||||
await foodStore.queryMobileFoodRecipeList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -19,9 +19,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import StatsCard from '@/components/Home/StatsCard.vue'
|
||||
import StatsCard from '@/components/StatsCard.vue'
|
||||
import { onMounted } from 'vue'
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
@@ -47,7 +47,7 @@ const getAverageCount = () => {
|
||||
}
|
||||
})
|
||||
|
||||
return foodStore.foodRecordList.length / Object.keys(result).length
|
||||
return (foodStore.foodRecordList.length / Object.keys(result).length).toFixed(2)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<el-dialog v-model="foodStore.foodMaterialDialog.visible"
|
||||
:title="foodStore.foodMaterialDialog.title"
|
||||
<el-dialog v-model="foodStore.foodMaterialDialogVisible"
|
||||
:title="foodStore.foodMaterialApiType === 'ADD' ? '新增食材' : '编辑食材'"
|
||||
center @open="openDialogEvent"
|
||||
class="food-material-dialog">
|
||||
<el-form ref="formRef" :model="foodStore.foodMaterialDialog.data"
|
||||
:rules="rules">
|
||||
<el-form ref="formRef" :model="foodStore.currentFoodMaterial"
|
||||
:rules="rules" label-width="auto">
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select
|
||||
v-model="foodStore.foodMaterialDialog.data.type"
|
||||
v-model="foodStore.currentFoodMaterial.type"
|
||||
placeholder="请选择类型">
|
||||
<el-option
|
||||
v-for="(item, index) in foodMaterialTypeList"
|
||||
@@ -17,14 +17,14 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="foodStore.foodMaterialDialog.data.name" autocomplete="off"
|
||||
<el-input v-model="foodStore.currentFoodMaterial.name" autocomplete="off"
|
||||
placeholder="请输入名称" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="分量" prop="amount">
|
||||
<el-input v-model="foodStore.foodMaterialDialog.data.amount" autocomplete="off"
|
||||
<el-input v-model="foodStore.currentFoodMaterial.amount" autocomplete="off"
|
||||
placeholder="请输入分量(1斤/2勺/适量)" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
@@ -41,10 +41,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { nextTick, reactive, ref } from 'vue'
|
||||
import { FormRules } from 'element-plus'
|
||||
import { foodMaterialRules } from '@/utils/element/elRules'
|
||||
import { foodMaterialRules } from '@/utils/element/elRules.ts'
|
||||
const rules = reactive<FormRules>(foodMaterialRules)
|
||||
|
||||
const formRef = ref()
|
||||
@@ -68,22 +68,22 @@ const confirmClick = () => {
|
||||
formRef.value.validate().then(async () => {
|
||||
if (foodStore.foodMaterialApiType === 'UPDATE') {
|
||||
const { editFoodMaterialIndex: index } = foodStore
|
||||
foodStore.foodRecipeDialog.data.materialList[index] = foodStore.foodMaterialDialog.data
|
||||
foodStore.currentFoodRecipe.materialList[index] = foodStore.currentFoodMaterial
|
||||
} else {
|
||||
foodStore.foodRecipeDialog.data.materialList.push(foodStore.foodMaterialDialog.data)
|
||||
foodStore.currentFoodRecipe.materialList.push(foodStore.currentFoodMaterial)
|
||||
}
|
||||
foodStore.foodMaterialDialog.visible = false
|
||||
foodStore.foodMaterialDialogVisible = false
|
||||
})
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
foodStore.foodMaterialDialog.visible = false
|
||||
foodStore.foodMaterialDialogVisible = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.food-material-dialog {
|
||||
width: 30%;
|
||||
width: 80%;
|
||||
|
||||
.el-dialog__body {
|
||||
// height: 50vh;
|
||||
51
src/components/Food/Form/FoodMaterialForm.vue
Normal file
51
src/components/Food/Form/FoodMaterialForm.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="material-form">
|
||||
<div style="align-self: center;">
|
||||
<el-button type="primary" @click="handleAddClick">新增</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :data="foodStore.currentFoodRecipe.materialList"
|
||||
border stripe class="material-table">
|
||||
<el-table-column prop="type" label="类型" align="center" min-width="15%"/>
|
||||
<el-table-column prop="name" label="名称" align="center" min-width="20%"/>
|
||||
<el-table-column prop="amount" label="分量" align="center" min-width="20%"/>
|
||||
<el-table-column label="操作" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" text style="margin: 0 10px 0 0;padding: 0;"
|
||||
@click="handleEditClick(scope.$index, scope.row)">编辑</el-button>
|
||||
<el-button type="danger" text style="margin: 0;padding: 0;"
|
||||
@click="handleDeleteClick(scope.$index, scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { IFoodMaterial } from '@/types/food.ts'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
const handleAddClick = () => {
|
||||
foodStore.foodMaterialApiType = 'ADD'
|
||||
foodStore.currentFoodMaterial = foodStore.getEmptyFoodMaterial()
|
||||
foodStore.foodMaterialDialogVisible = true
|
||||
}
|
||||
|
||||
const handleEditClick = (index: number, material: IFoodMaterial) => {
|
||||
foodStore.editFoodMaterialIndex = index
|
||||
foodStore.foodMaterialApiType = 'UPDATE'
|
||||
foodStore.currentFoodMaterial = deepCopyObject(material)
|
||||
foodStore.foodMaterialDialogVisible = true
|
||||
}
|
||||
|
||||
const handleDeleteClick = (index: number, material: IFoodMaterial) => {
|
||||
foodStore.foodMaterialApiType = 'DELETE'
|
||||
commonElMessageBox(`确认删除该食材: ${material.name}?`).then(() => {
|
||||
foodStore.currentFoodRecipe.materialList.splice(index, 1)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
139
src/components/Food/Form/FoodStepDialog.vue
Normal file
139
src/components/Food/Form/FoodStepDialog.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<el-dialog v-model="foodStore.foodStepDialogVisible"
|
||||
:title="foodStore.foodStepApiType === 'ADD' ? '新增步骤' : '编辑步骤'"
|
||||
center @open="openDialogEvent"
|
||||
class="food-step-dialog">
|
||||
<el-form ref="formRef" :model="foodStore.currentFoodStep"
|
||||
:rules="rules" label-width="auto">
|
||||
<el-form-item label="内容" prop="content">
|
||||
<el-input v-model="foodStore.currentFoodStep.content" autocomplete="off"
|
||||
placeholder="请输入内容" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="图片">
|
||||
<el-upload
|
||||
v-model:file-list="imageFileList"
|
||||
list-type="picture-card"
|
||||
:accept="acceptImageTypes"
|
||||
:limit="1"
|
||||
:before-upload="beforeUpload"
|
||||
:http-request="httpRequest"
|
||||
:on-success="handleSuccess"
|
||||
:on-exceed="handleExceed"
|
||||
:before-remove="beforeRemove"
|
||||
:on-remove="handleRemove"
|
||||
>
|
||||
<el-icon><Plus /></el-icon>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
请上传小于10M的图片
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">保存</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { ref, reactive, nextTick, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox, FormRules, UploadProps, UploadRawFile, UploadRequestOptions, UploadUserFile } from 'element-plus'
|
||||
import { foodStepRules } from '@/utils/element/elRules.ts'
|
||||
import { acceptImageTypes } from '@/utils/file.ts'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { beforeUploadImage, httpRequestFile } from '@/utils/element/elUpload.ts'
|
||||
|
||||
const rules = reactive<FormRules>(foodStepRules)
|
||||
|
||||
const formRef = ref()
|
||||
const foodStore = useFoodStore()
|
||||
const imageFileList = ref<UploadUserFile[]>([])
|
||||
|
||||
onMounted(async () => {
|
||||
initImageFileList()
|
||||
})
|
||||
|
||||
const initImageFileList = () => {
|
||||
imageFileList.value = []
|
||||
const { imageUrl } = foodStore.currentFoodStep
|
||||
if (imageUrl) {
|
||||
imageFileList.value.push({
|
||||
name: 'image',
|
||||
url: imageUrl
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
|
||||
return beforeUploadImage(rawFile)
|
||||
}
|
||||
|
||||
const httpRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => {
|
||||
return await httpRequestFile(foodStore.foodImagePath, options)
|
||||
}
|
||||
|
||||
const handleSuccess = (response: string) => {
|
||||
foodStore.currentFoodStep.imageUrl = response
|
||||
}
|
||||
|
||||
const handleExceed: UploadProps['onExceed'] = () => {
|
||||
ElMessage.warning('最多上传1张图片')
|
||||
}
|
||||
|
||||
const handleRemove: UploadProps['onRemove'] = () => {
|
||||
foodStore.currentFoodStep.imageUrl = ''
|
||||
}
|
||||
|
||||
const beforeRemove: UploadProps['beforeRemove'] = () => {
|
||||
return ElMessageBox.confirm('确认删除该文件?').then(() => true, () => false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开对话框事件
|
||||
*/
|
||||
const openDialogEvent = () => {
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击确认按钮
|
||||
*/
|
||||
const confirmClick = () => {
|
||||
formRef.value.validate()
|
||||
.then(async () => {
|
||||
if (foodStore.foodStepApiType === 'UPDATE') {
|
||||
const { editFoodStepIndex: index } = foodStore
|
||||
foodStore.currentFoodRecipe.stepList[index] = foodStore.currentFoodStep
|
||||
} else {
|
||||
foodStore.currentFoodRecipe.stepList.push(foodStore.currentFoodStep)
|
||||
}
|
||||
foodStore.foodStepDialogVisible = false
|
||||
})
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
foodStore.foodStepDialogVisible = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.food-step-dialog {
|
||||
width: 80%;
|
||||
|
||||
.el-dialog__body {
|
||||
// height: 50vh;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
72
src/components/Food/Form/FoodStepForm.vue
Normal file
72
src/components/Food/Form/FoodStepForm.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="step-form">
|
||||
<div style="align-self: center;">
|
||||
<el-button type="primary" @click="handleAddClick">新增</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :data="foodStore.currentFoodRecipe.stepList"
|
||||
border class="food-step-table">
|
||||
<el-table-column prop="content" label="内容" align="center" min-width="20%" />
|
||||
<el-table-column prop="imageUrl" label="图片" align="center" min-width="20%">
|
||||
<template #default="scope">
|
||||
<el-image v-if="scope.row.imageUrl" :src="scope.row.imageUrl" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" text style="margin: 0 10px 0 0;padding: 0;"
|
||||
@click="handleEditClick(scope.$index, scope.row)">编辑</el-button>
|
||||
<el-button type="danger" text style="margin: 0;padding: 0;"
|
||||
@click="handleDeleteClick(scope.$index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { IFoodStep } from '@/types/food.ts'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
const handleAddClick = () => {
|
||||
foodStore.foodStepApiType = 'ADD'
|
||||
foodStore.currentFoodStep = foodStore.getEmptyFoodStep()
|
||||
foodStore.foodStepDialogVisible = true
|
||||
}
|
||||
|
||||
const handleEditClick = (index: number, step: IFoodStep) => {
|
||||
foodStore.editFoodStepIndex = index
|
||||
foodStore.foodStepApiType = 'UPDATE'
|
||||
foodStore.currentFoodStep = deepCopyObject(step)
|
||||
foodStore.foodStepDialogVisible = true
|
||||
}
|
||||
|
||||
const handleDeleteClick = (index: number) => {
|
||||
commonElMessageBox('确认删除该步骤?').then(() => {
|
||||
foodStore.foodStepApiType = 'DELETE'
|
||||
foodStore.currentFoodRecipe.stepList.splice(index, 1)
|
||||
foodStore.currentFoodRecipe.stepList.forEach((item) => {
|
||||
if (item.sort > index) {
|
||||
item.sort -= 1
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.food-step-table {
|
||||
.el-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
max-height: 200px;
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
129
src/components/Health/HealthChart.vue
Normal file
129
src/components/Health/HealthChart.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div class="bill-chart common-chart"
|
||||
v-loading="healthStore.isLoading"
|
||||
element-loading-text="正在加载中...">
|
||||
<div class="chart-container card-item">
|
||||
<div class="content">
|
||||
<span class="title">📊体重趋势</span>
|
||||
</div>
|
||||
<div class="chart" ref="weightDailyChartRef"/>
|
||||
</div>
|
||||
|
||||
<div class="chart-container card-item">
|
||||
<div class="content">
|
||||
<span class="title">📊睡眠时长统计图</span>
|
||||
</div>
|
||||
<div class="chart" ref="sleepDailyChartRef"/>
|
||||
</div>
|
||||
|
||||
<div class="chart-container card-item">
|
||||
<div class="content">
|
||||
<span class="title">📊运动时长统计</span>
|
||||
</div>
|
||||
<div class="chart" ref="healthDurationChartRef"/>
|
||||
</div>
|
||||
|
||||
<div class="chart-container card-item">
|
||||
<div class="content">
|
||||
<span class="title">📊运动类别统计</span>
|
||||
</div>
|
||||
<div class="chart" ref="healthCategoryChartRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import { lineChartOptions, barChartOptions, pieChartOptions } from 'vue3-common/utils/eChartsUtil'
|
||||
import { useHealthStore } from '@/store/health'
|
||||
import { useAppStore } from '@/store/app.ts'
|
||||
import { formatDate } from 'vue3-common/utils/dateUtil'
|
||||
|
||||
const healthStore = useHealthStore()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const weightDailyChartRef = ref<HTMLElement>()
|
||||
const sleepDailyChartRef = ref<HTMLElement>()
|
||||
const healthDurationChartRef = ref<HTMLElement>()
|
||||
const healthCategoryChartRef = ref<HTMLElement>()
|
||||
|
||||
let weightDailyChart: echarts.ECharts
|
||||
let sleepDailyChart: echarts.ECharts
|
||||
let healthDurationChart: echarts.ECharts
|
||||
let healthCategoryChart: echarts.ECharts
|
||||
|
||||
watch(() => healthStore.isRefresh, () => {
|
||||
updateChart()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
weightDailyChart = echarts.init(weightDailyChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
||||
sleepDailyChart = echarts.init(sleepDailyChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
||||
healthDurationChart = echarts.init(healthDurationChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
||||
healthCategoryChart = echarts.init(healthCategoryChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
||||
})
|
||||
|
||||
const updateChart = () => {
|
||||
const MAX_CATEGORY_COUNT = 5
|
||||
|
||||
// 体重趋势统计图
|
||||
const weightRecordList = healthStore.healthRecordList
|
||||
.filter((item) => item.weight !== 0)
|
||||
|
||||
const weightXAxis = weightRecordList.map((item) => {
|
||||
return formatDate(item.date, 'MM-DD')
|
||||
}).reverse()
|
||||
const weightYAxis = weightRecordList.map((item) => item.weight).reverse()
|
||||
const sortedRecordList = weightRecordList.sort((a, b) => a.weight - b.weight)
|
||||
|
||||
weightDailyChart.setOption(lineChartOptions('日期', weightXAxis, '体重(千克)', weightYAxis))
|
||||
|
||||
if (sortedRecordList.length > 0) {
|
||||
weightDailyChart.setOption({
|
||||
yAxis: {
|
||||
min: Math.floor(sortedRecordList[0].weight),
|
||||
max: Math.ceil(sortedRecordList[sortedRecordList.length - 1].weight)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 睡眠时长统计图
|
||||
const sleepRecordList = healthStore.healthRecordList
|
||||
.filter((item) => item.sleepDuration !== null)
|
||||
.sort((a, b) => (a.date > b.date ? -1 : 1))
|
||||
|
||||
const sleepXAxis = sleepRecordList.map((item) => {
|
||||
return formatDate(item.date, 'MM-DD')
|
||||
}).reverse()
|
||||
const sleepYAxis = sleepRecordList.map((item) => item.sleepDuration).reverse() as number[]
|
||||
|
||||
sleepDailyChart.setOption(barChartOptions('日期', sleepXAxis, '时间(小时)', sleepYAxis))
|
||||
|
||||
// 运动量统计图
|
||||
const sportRecordList = healthStore.healthRecordList
|
||||
.filter((item) => item.sportProject !== '')
|
||||
.sort((a, b) => (a.date > b.date ? -1 : 1))
|
||||
|
||||
const durationXAxis = sportRecordList.map((item) => {
|
||||
return formatDate(item.date, 'MM-DD')
|
||||
}).reverse()
|
||||
const durationYAxis = sportRecordList.map((item) => item.sportDuration).reverse()
|
||||
|
||||
healthDurationChart.setOption(barChartOptions('日期', durationXAxis, '时间(分钟)', durationYAxis))
|
||||
|
||||
// 类别统计图
|
||||
const healthCategoryList = healthStore.healthRecordList.reduce((acc, item) => {
|
||||
if (item.sportProject && item.sportDuration > 0) {
|
||||
const existing = acc.find((project) => project.name === item.sportProject)
|
||||
if (existing) {
|
||||
existing.value += item.sportDuration
|
||||
} else {
|
||||
acc.push({ name: item.sportProject, value: item.sportDuration })
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
healthCategoryChart.setOption(pieChartOptions('名称', '分钟', healthCategoryList.slice(0, MAX_CATEGORY_COUNT)))
|
||||
}
|
||||
</script>
|
||||
179
src/components/Health/HealthForm.vue
Normal file
179
src/components/Health/HealthForm.vue
Normal file
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<el-form :model="healthStore.currentHealth" class="health-form card-item">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<i class="fa-regular fa-calendar-check"></i>
|
||||
<span>日期</span>
|
||||
</template>
|
||||
<el-date-picker v-model="healthStore.currentHealth.date"
|
||||
type="date" :disabled="true"
|
||||
style="width: 150px;"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<i class="fa-solid fa-person-running"></i>
|
||||
<span>运动项目</span>
|
||||
</template>
|
||||
|
||||
<el-select v-model="healthStore.currentHealth.sportProject"
|
||||
placeholder="请选择运行项目" clearable style="width: 150px;">
|
||||
<el-option v-for="(item, index) in projectList" :key="index"
|
||||
:label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<i class="fa-solid fa-clock"></i>
|
||||
<span>运动时长</span>
|
||||
</template>
|
||||
|
||||
<el-input-number v-model="healthStore.currentHealth.sportDuration"
|
||||
:min="0" :max="300" :precision="0"
|
||||
style="width: 120px;"></el-input-number>
|
||||
|
||||
<span style="margin-left: 5px;">分钟</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<i class="fa-solid fa-weight-scale"></i>
|
||||
<span>体重</span>
|
||||
</template>
|
||||
|
||||
<el-input-number v-model="healthStore.currentHealth.weight"
|
||||
:min="0" :max="200"
|
||||
style="width: 120px;"></el-input-number>
|
||||
|
||||
<span style="margin-left: 5px;">千克</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<i class="fa-solid fa-moon"></i>
|
||||
<span>睡眠开始时间</span>
|
||||
</template>
|
||||
|
||||
<el-time-picker
|
||||
v-model="healthStore.currentHealth.sleepStartTime"
|
||||
clearable :editable="false"
|
||||
placeholder="请选择睡眠开始时间"
|
||||
style="width: 180px"
|
||||
format="HH:mm"
|
||||
value-format="HH:mm"
|
||||
@clear="healthStore.currentHealth.sleepStartTime = ''"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<i class="fa-solid fa-sun"></i>
|
||||
<span>睡眠结束时间</span>
|
||||
</template>
|
||||
|
||||
<el-time-picker
|
||||
v-model="healthStore.currentHealth.sleepEndTime"
|
||||
clearable :editable="false"
|
||||
placeholder="请选择睡眠结束时间"
|
||||
style="width: 180px"
|
||||
format="HH:mm"
|
||||
value-format="HH:mm"
|
||||
@clear="healthStore.currentHealth.sleepEndTime = ''"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<i class="fa-solid fa-hourglass-start"></i>
|
||||
<span>睡眠时长</span>
|
||||
</template>
|
||||
|
||||
<span>{{ healthStore.currentHealth.sleepDuration }}</span>
|
||||
<span style="margin-left: 5px;">小时</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="align-self: center;">
|
||||
<el-button type="primary" @click="onSubmit"
|
||||
:disabled="isBeforeDate(formatDate(new Date()), healthStore.selectDate)">
|
||||
确认
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useHealthStore } from '@/store/health'
|
||||
import { formatDate, isBeforeDate } from 'vue3-common/utils/dateUtil'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const healthStore = useHealthStore()
|
||||
|
||||
const projectList = ['羽毛球', '乒乓球', '跑步', '其他']
|
||||
|
||||
const onSubmit = async () => {
|
||||
const { sportProject, sportDuration, weight,
|
||||
sleepStartTime, sleepEndTime } = healthStore.currentHealth
|
||||
if (sportProject === '' && sportDuration === 0 && weight === 0
|
||||
&& sleepStartTime === '' && sleepEndTime === '') {
|
||||
return
|
||||
}
|
||||
|
||||
if (sportDuration) {
|
||||
if (!sportProject) {
|
||||
ElMessage.error('请选择运动项目')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (sleepStartTime && sleepEndTime) {
|
||||
healthStore.currentHealth.sleepDuration = calculateSleepDuration(sleepStartTime, sleepEndTime)
|
||||
}
|
||||
|
||||
await healthStore.updateHealthDay()
|
||||
healthStore.currentHealth = healthStore.getHealthDay(healthStore.selectDate)
|
||||
}
|
||||
|
||||
const calculateSleepDuration = (startTime: string, endTime: string) => {
|
||||
const start = dayjs(startTime, 'HH:mm')
|
||||
let end = dayjs(endTime, 'HH:mm')
|
||||
|
||||
// 处理跨天
|
||||
if (end.isSameOrBefore(start)) {
|
||||
end = end.add(1, 'day')
|
||||
}
|
||||
|
||||
// 计算时间差(小时)
|
||||
return end.diff(start, 'hour', true)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.health-form {
|
||||
padding: 10px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.el-form-item {
|
||||
justify-content: space-between;
|
||||
|
||||
.el-form-item__label {
|
||||
display: grid;
|
||||
grid-template-columns: 20px 1fr;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
|
||||
i {
|
||||
font-size: 1.2rem;
|
||||
color: #DE3163;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form-item__content {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
41
src/components/Health/HealthStats.vue
Normal file
41
src/components/Health/HealthStats.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="common-statistics">
|
||||
<stats-card
|
||||
title="平均体重" color="#CA6C65" unit="千克" icon="fa-solid fa-weight-scale"
|
||||
:value="formatAmount(healthStats.averageWeight)" />
|
||||
|
||||
<stats-card
|
||||
title="运动时长" color="#6FBB69" unit="分钟" icon="fa-solid fa-person-walking"
|
||||
:value="healthStats.totalDuration" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import StatsCard from '@/components/StatsCard.vue'
|
||||
import { useHealthStore } from '@/store/health'
|
||||
import { ref, watch } from 'vue'
|
||||
import { formatAmount } from 'vue3-common/utils/numberUtil'
|
||||
import record from '@/views/travel/record.vue'
|
||||
import { max } from '@popperjs/core/lib/utils/math'
|
||||
|
||||
const healthStore = useHealthStore()
|
||||
|
||||
watch(() => healthStore.isRefresh, () => {
|
||||
updateStats()
|
||||
})
|
||||
|
||||
const healthStats = ref({
|
||||
averageWeight: 0,
|
||||
totalDuration: 0
|
||||
})
|
||||
|
||||
const updateStats = () => {
|
||||
const recordList = healthStore.healthRecordList
|
||||
const totalWeight = recordList.reduce((sum, item) => sum + item.weight, 0)
|
||||
|
||||
if (recordList.length > 0) {
|
||||
healthStats.value.averageWeight = totalWeight / recordList.length
|
||||
healthStats.value.totalDuration = recordList.reduce((sum, item) => sum + item.sportDuration, 0)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,32 +0,0 @@
|
||||
<template>
|
||||
<div class="date-list">
|
||||
<!-- <el-empty v-if="planStore.planList.length === 0" />-->
|
||||
|
||||
<el-scrollbar>
|
||||
<date-card v-for="(item, index) in 4"
|
||||
:key="index" :plan="item">
|
||||
</date-card>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import DateCard from '@/components/Home/Anniversary/AnniversaryCard.vue'
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/home.variable.module.scss";
|
||||
|
||||
.date-list {
|
||||
height: calc(100vh - 120px);
|
||||
|
||||
.el-scrollbar {
|
||||
.el-scrollbar__view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,166 +0,0 @@
|
||||
<template>
|
||||
<div class="bill-setting">
|
||||
<div class="button-container">
|
||||
<el-button type="primary" @click="addNewBookClick">新增账本</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
:data="billStore.billBookList"
|
||||
border stripe
|
||||
:header-cell-style="tableHeaderStyle()"
|
||||
:cell-style="tableCellStyle()"
|
||||
:row-style="tableRowStyle()"
|
||||
style="width: 100%"
|
||||
class="card-item">
|
||||
<el-table-column type="index" align="center" width="50"/>
|
||||
<el-table-column prop="name" label="名称" align="center" width="100"/>
|
||||
<el-table-column label="图标" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<i :class="scope.row.icon" :style="{color: scope.row.color, fontSize: '24px'}"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" size="small" @click="editBookClick(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="small" @click="deleteBookClick(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog v-model="billInfo.billBookDialog.visible"
|
||||
:title="billInfo.billBookDialog.title"
|
||||
center width="80%" @open="openDialogEvent">
|
||||
<el-form ref="formRef" :model="billInfo.billBookDialog.data"
|
||||
:rules="rules" label-position="top" label-width="100px">
|
||||
<el-form-item label="账本名称" prop="name">
|
||||
<el-input v-model="billInfo.billBookDialog.data.name" autocomplete="off"
|
||||
placeholder="请输入类型名称"
|
||||
:maxlength="10" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型图标" prop="icon">
|
||||
<el-input v-model="billInfo.billBookDialog.data.icon" autocomplete="off"
|
||||
placeholder="请输入类型图标"
|
||||
:maxlength="40" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标颜色" prop="color">
|
||||
<el-color-picker v-model="billInfo.billBookDialog.data.color" />
|
||||
</el-form-item>
|
||||
<el-form-item label="图标预览">
|
||||
<i :class="billInfo.billBookDialog.data.icon"
|
||||
:style="{color: billInfo.billBookDialog.data.color, fontSize: '24px'}"></i>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { useBillStore } from '@/store/bill'
|
||||
import { ElMessage, FormRules } from 'element-plus'
|
||||
import { IBillBook } from '@/types/bill'
|
||||
import { billBookRules } from '@/utils/element/elRules'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import type { IDialog, IHandleApi } from 'vue3-common/types'
|
||||
import { addBillBookApi, updateBillBookApi } from '@/apis/bill'
|
||||
import { tableCellStyle, tableHeaderStyle, tableRowStyle } from 'vue3-common/utils/elUtil'
|
||||
|
||||
const formRef = ref()
|
||||
const rules = reactive<FormRules>(billBookRules)
|
||||
const billStore = useBillStore()
|
||||
|
||||
const billInfo = reactive({
|
||||
setBillBookType: 'ADD' as IHandleApi,
|
||||
billBookDialog: {
|
||||
title: '',
|
||||
visible: false,
|
||||
data: {}
|
||||
} as IDialog<IBillBook>
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await billStore.queryBillBook()
|
||||
})
|
||||
|
||||
/**
|
||||
* 点击新增账本按钮
|
||||
*/
|
||||
const addNewBookClick = () => {
|
||||
billInfo.setBillBookType = 'ADD'
|
||||
billInfo.billBookDialog = {
|
||||
title: '新增账本',
|
||||
visible: true,
|
||||
data: {
|
||||
name: '',
|
||||
icon: '',
|
||||
color: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击编辑账本按钮
|
||||
* @param book 账本
|
||||
*/
|
||||
const editBookClick = async (book: IBillBook) => {
|
||||
billInfo.setBillBookType = 'UPDATE'
|
||||
billInfo.billBookDialog = {
|
||||
title: '编辑账本',
|
||||
visible: true,
|
||||
data: deepCopyObject(book)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击删除账本按钮
|
||||
* @param book 账本
|
||||
*/
|
||||
const deleteBookClick = (book: IBillBook) => {
|
||||
billInfo.setBillBookType = 'DELETE'
|
||||
ElMessage.error('暂不支持该功能')
|
||||
}
|
||||
|
||||
const openDialogEvent = () => {
|
||||
nextTick(() => {
|
||||
formRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
const setBillBookApi = async (id?: number) => {
|
||||
switch (billInfo.setBillBookType) {
|
||||
case 'ADD':
|
||||
await addBillBookApi(billInfo.billBookDialog.data)
|
||||
ElMessage.success('新增账本成功')
|
||||
break
|
||||
case 'UPDATE':
|
||||
await updateBillBookApi(id as number, billInfo.billBookDialog.data)
|
||||
ElMessage.success('更新账本成功')
|
||||
break
|
||||
case 'DELETE':
|
||||
ElMessage.success('删除账本成功')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
await billStore.queryBillBook()
|
||||
billInfo.billBookDialog.visible = false
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
billInfo.billBookDialog.visible = false
|
||||
}
|
||||
|
||||
const confirmClick = async () => {
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
await setBillBookApi(billInfo.billBookDialog.data.id)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,222 +0,0 @@
|
||||
<template>
|
||||
<div class="bill-setting">
|
||||
<div class="button-container">
|
||||
<el-select
|
||||
v-model="billInfo.bookName"
|
||||
placeholder="请选择账本名称"
|
||||
@focus="focusBookNameEvent"
|
||||
@change="selectBookNameEvent"
|
||||
style="width: 150px;">
|
||||
<el-option
|
||||
v-for="(item, index) in billInfo.billBookList"
|
||||
:key="index" :label="item.name" :value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-button type="primary" @click="addNewCategoryClick">新增类别</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
:data="billInfo.billCategoryList"
|
||||
border stripe
|
||||
:header-cell-style="tableHeaderStyle()"
|
||||
:cell-style="tableCellStyle()"
|
||||
:row-style="tableRowStyle()"
|
||||
class="card-item">
|
||||
<el-table-column type="index" align="center" width="50"/>
|
||||
<el-table-column prop="name" label="名称" align="center" width="80"/>
|
||||
<el-table-column label="类型" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.type === 'expensive'" effect="dark" color="#CA6C65">支出</el-tag>
|
||||
<el-tag v-else effect="dark" color="#6FBB69">收入</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="图标" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<i :class="scope.row.icon" :style="{color: scope.row.color, fontSize: '24px'}"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" size="small" @click="editCategoryClick(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="small" @click="deleteCategoryClick(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog v-model="billInfo.billCategoryDialog.visible"
|
||||
:title="billInfo.billCategoryDialog.title"
|
||||
center width="80%" @open="openDialogEvent">
|
||||
<el-form ref="formRef" :model="billInfo.billCategoryDialog.data"
|
||||
:rules="rules" label-position="top" label-width="100px">
|
||||
<el-form-item label="账本名称" prop="bookName">
|
||||
<el-select
|
||||
v-model="billInfo.billCategoryDialog.data.bookName"
|
||||
placeholder="请选择账本名称"
|
||||
@focus="focusBookNameEvent">
|
||||
<el-option
|
||||
v-for="(item, index) in billInfo.billBookList"
|
||||
:key="index" :label="item.name" :value="item.name"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="类别名称" prop="name">
|
||||
<el-input v-model="billInfo.billCategoryDialog.data.name" autocomplete="off"
|
||||
placeholder="请输入类型名称"
|
||||
:maxlength="10" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型名称" prop="type">
|
||||
<el-radio-group v-model="billInfo.billCategoryDialog.data.type">
|
||||
<el-radio value="expensive">支出</el-radio>
|
||||
<el-radio value="income">收入</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="类别图标" prop="icon">
|
||||
<el-input v-model="billInfo.billCategoryDialog.data.icon" autocomplete="off"
|
||||
placeholder="请输入类型图标"
|
||||
:maxlength="40" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标颜色" prop="color">
|
||||
<el-color-picker v-model="billInfo.billCategoryDialog.data.color" />
|
||||
</el-form-item>
|
||||
<el-form-item label="图标预览">
|
||||
<i :class="billInfo.billCategoryDialog.data.icon"
|
||||
:style="{color: billInfo.billCategoryDialog.data.color, fontSize: '24px'}"></i>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { useBillStore } from '@/store/bill'
|
||||
import { IBillBook, IBillCategory } from '@/types/bill'
|
||||
import { ElMessage, FormRules } from 'element-plus'
|
||||
import { billCategoryRules } from '@/utils/element/elRules'
|
||||
import { addBillCategoryApi, updateBillCategoryApi } from '@/apis/bill'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { tableHeaderStyle, tableRowStyle, tableCellStyle } from 'vue3-common/utils/elUtil'
|
||||
import type { IDialog, IHandleApi } from 'vue3-common/types'
|
||||
|
||||
const formRef = ref()
|
||||
const rules = reactive<FormRules>(billCategoryRules)
|
||||
const billStore = useBillStore()
|
||||
|
||||
const billInfo = reactive({
|
||||
bookName: '日常账本',
|
||||
setBillCategoryType: 'ADD' as IHandleApi,
|
||||
billCategoryDialog: {
|
||||
title: '',
|
||||
visible: false,
|
||||
data: {}
|
||||
} as IDialog<IBillCategory>,
|
||||
billBookList: [] as IBillBook[],
|
||||
billCategoryList: [] as IBillCategory[]
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await billStore.queryBillCategory()
|
||||
queryBookCategoryByBookName(billInfo.bookName)
|
||||
})
|
||||
|
||||
const selectBookNameEvent = (value: string) => {
|
||||
queryBookCategoryByBookName(value)
|
||||
}
|
||||
|
||||
const queryBookCategoryByBookName = (bookName: string) => {
|
||||
billInfo.billCategoryList = billStore.billCategoryList.filter((item) => {
|
||||
return item.bookName === bookName
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击新增类别按钮
|
||||
*/
|
||||
const addNewCategoryClick = () => {
|
||||
billInfo.setBillCategoryType = 'ADD'
|
||||
billInfo.billCategoryDialog = {
|
||||
title: '新增账单类别',
|
||||
visible: true,
|
||||
data: {
|
||||
bookName: '',
|
||||
name: '',
|
||||
type: '',
|
||||
icon: '',
|
||||
color: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击编辑类别按钮
|
||||
* @param category 类别
|
||||
*/
|
||||
const editCategoryClick = async (category: IBillCategory) => {
|
||||
billInfo.setBillCategoryType = 'UPDATE'
|
||||
billInfo.billCategoryDialog = {
|
||||
title: '编辑账单类别',
|
||||
visible: true,
|
||||
data: deepCopyObject(category)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击删除类别按钮
|
||||
* @param category 类别
|
||||
*/
|
||||
const deleteCategoryClick = (category: IBillCategory) => {
|
||||
billInfo.setBillCategoryType = 'DELETE'
|
||||
ElMessage.error('暂不支持该功能')
|
||||
}
|
||||
|
||||
const openDialogEvent = () => {
|
||||
nextTick(() => {
|
||||
formRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
const focusBookNameEvent = async () => {
|
||||
await billStore.queryBillBook()
|
||||
billInfo.billBookList = billStore.billBookList
|
||||
}
|
||||
|
||||
const setBillCategoryApi = async (id?: number) => {
|
||||
switch (billInfo.setBillCategoryType) {
|
||||
case 'ADD':
|
||||
await addBillCategoryApi(billInfo.billCategoryDialog.data)
|
||||
ElMessage.success('新增账单类别成功')
|
||||
break
|
||||
case 'UPDATE':
|
||||
await updateBillCategoryApi(id as number, billInfo.billCategoryDialog.data)
|
||||
ElMessage.success('更新账单类别成功')
|
||||
break
|
||||
case 'DELETE':
|
||||
ElMessage.success('删除账单类别成功')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
await billStore.queryBillCategory()
|
||||
billInfo.billCategoryDialog.visible = false
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
billInfo.billCategoryDialog.visible = false
|
||||
}
|
||||
|
||||
const confirmClick = async () => {
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
await setBillCategoryApi(billInfo.billCategoryDialog.data.id)
|
||||
queryBookCategoryByBookName(billInfo.bookName)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,235 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="billStore.billDialog.visible"
|
||||
title="账单内容" center class="bill-dialog"
|
||||
@open="openDialogEvent">
|
||||
<el-form ref="formRef" :model="billStore.billDialog.data"
|
||||
:rules="rules" label-width="80px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="账本类型" prop="bookName">
|
||||
<el-radio-group v-model="billStore.billDialog.data.bookName"
|
||||
@change="changeBillBookNameEvent">
|
||||
<el-radio v-for="(item, index) in billStore.billBookList"
|
||||
:value="item.name" :key="index">
|
||||
<template #default>
|
||||
<i :class="item.icon" :style="{color: item.color}"/>
|
||||
<span style="margin-left: 5px;">{{ item.name }}</span>
|
||||
</template>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单类别" prop="type">
|
||||
<el-radio-group v-model="billStore.billDialog.data.type"
|
||||
@change="changeBillCategoryEvent">
|
||||
<el-radio v-for="(item, index) in billInfo.billTypeList"
|
||||
:value="item" :key="index">
|
||||
{{ getBillTypeName(item) }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单分类" prop="category">
|
||||
<el-radio-group v-model="billStore.billDialog.data.category">
|
||||
<el-radio v-for="(item, index) in billInfo.billCategoryList"
|
||||
:value="item.name" :key="index">
|
||||
<template #default>
|
||||
<i :class="item.icon" :style="{color: item.color}"/>
|
||||
<span style="margin-left: 5px;">{{ item.name }}</span>
|
||||
</template>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单时间" prop="date">
|
||||
<el-date-picker
|
||||
v-model="billStore.billDialog.data.date"
|
||||
type="date" :editable="false" placeholder="请选择账单时间"
|
||||
value-format="YYYY-MM-DD"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单地点" prop="location">
|
||||
<el-input v-model="billStore.billDialog.data.location" autocomplete="off"
|
||||
placeholder="请输入账单地点" clearable
|
||||
show-word-limit maxlength="10">
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon"><location/></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单账户" prop="payAccount">
|
||||
<el-radio-group v-model="billStore.billDialog.data.payAccount">
|
||||
<el-radio v-for="(item, index) in billStore.billPayList"
|
||||
:value="item.name" :key="index">
|
||||
<template #default>
|
||||
<i :class="item.icon" :style="{color: item.color}"/>
|
||||
<span style="margin-left: 5px;">{{ item.name }}</span>
|
||||
</template>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单金额" prop="amount">
|
||||
<amount-input v-model="billStore.billDialog.data.amount"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="账单内容" prop="content">
|
||||
<el-input v-model="billStore.billDialog.data.content" autocomplete="off"
|
||||
placeholder="请输入账单内容" clearable
|
||||
show-word-limit maxlength="10">
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon"><document/></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="账单备注">
|
||||
<el-input v-model="billStore.billDialog.data.remark" type="textarea"
|
||||
placeholder="请输入账单备注" clearable
|
||||
:rows="5" show-word-limit maxlength="200">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账单图片">
|
||||
<upload-image v-model="billStore.billDialog.data.imageList"
|
||||
:service-url="fileServiceUrl"
|
||||
:service-file-root-path="serviceFileRootPath"
|
||||
:image-path="billStore.billImagePath"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">
|
||||
{{ billStore.billApiType === 'UPDATE' ? '编辑' : '新增' }}
|
||||
</el-button>
|
||||
<el-button v-if="billStore.billApiType === 'UPDATE'"
|
||||
type="danger" @click="deleteClick">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { UploadImage, AmountInput } from 'vue3-common'
|
||||
import { useBillStore } from '@/store/bill'
|
||||
import { Location, Document } from '@element-plus/icons-vue'
|
||||
import { FormRules } from 'element-plus'
|
||||
import { billRecordRules } from '@/utils/element/elRules'
|
||||
import { nextTick, reactive, ref } from 'vue'
|
||||
import { IBillCategory } from '@/types/bill'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
import { fileServiceUrl, serviceFileRootPath } from '@/utils'
|
||||
|
||||
const formRef = ref()
|
||||
const rules = reactive<FormRules>(billRecordRules)
|
||||
const billStore = useBillStore()
|
||||
|
||||
const billInfo = reactive({
|
||||
billTypeList: [] as string[],
|
||||
billCategoryList: [] as IBillCategory[]
|
||||
})
|
||||
|
||||
/**
|
||||
* 打开对话框事件
|
||||
*/
|
||||
const openDialogEvent = async () => {
|
||||
// 如果是新增账单 默认选择第一个账本
|
||||
if (billStore.billApiType !== 'UPDATE') {
|
||||
billStore.billDialog.data.bookName = billStore.billBookList[0].name
|
||||
}
|
||||
getBillTypeByBookName(billStore.billDialog.data.bookName)
|
||||
|
||||
// 如果是新增账单 默认选择一个类别
|
||||
if (billStore.billApiType !== 'UPDATE') {
|
||||
billStore.billDialog.data.type = billInfo.billTypeList[0]
|
||||
}
|
||||
getBillCategory()
|
||||
|
||||
// 如果是新增账单 默认选择一个分类
|
||||
if (billStore.billApiType !== 'UPDATE') {
|
||||
billStore.billDialog.data.category = billInfo.billCategoryList[0].name
|
||||
billStore.billDialog.data.payAccount = billStore.billPayList[0].name
|
||||
}
|
||||
|
||||
await nextTick(() => {
|
||||
formRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取账单类型名称
|
||||
* @param type 账单类型
|
||||
*/
|
||||
const getBillTypeName = (type: string) => {
|
||||
return type === 'expensive' ? '支出' : '收入'
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择账本事件
|
||||
* @param value 账本名称
|
||||
*/
|
||||
const changeBillBookNameEvent = (value: string) => {
|
||||
getBillTypeByBookName(value)
|
||||
billStore.billDialog.data.type = billInfo.billTypeList[0]
|
||||
getBillCategory()
|
||||
billStore.billDialog.data.category = billInfo.billCategoryList[0].name
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择账单类别事件
|
||||
*/
|
||||
const changeBillCategoryEvent = () => {
|
||||
getBillCategory()
|
||||
billStore.billDialog.data.category = billInfo.billCategoryList[0].name
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过账本获取账单类型
|
||||
* @param bookName 账本
|
||||
*/
|
||||
const getBillTypeByBookName = (bookName: string) => {
|
||||
billInfo.billTypeList = []
|
||||
billStore.billCategoryList.forEach((item) => {
|
||||
if (item.bookName === bookName && !billInfo.billTypeList.includes(item.type)) {
|
||||
billInfo.billTypeList.push(item.type)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取账单类别
|
||||
*/
|
||||
const getBillCategory = () => {
|
||||
billInfo.billCategoryList = billStore.billCategoryList.filter((value) => {
|
||||
return value.bookName === billStore.billDialog.data.bookName
|
||||
&& value.type === billStore.billDialog.data.type
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击确认按钮
|
||||
*/
|
||||
const confirmClick = () => {
|
||||
formRef.value.validate().then(() => {
|
||||
billStore.handleBillApi(billStore.billDialog.data)
|
||||
})
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
billStore.billDialog.visible = false
|
||||
}
|
||||
|
||||
const deleteClick = () => {
|
||||
commonElMessageBox('是否确认删除该账单内容?').then(() => {
|
||||
billStore.billApiType = 'DELETE'
|
||||
billStore.handleBillApi(billStore.billDialog.data)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,166 +0,0 @@
|
||||
<template>
|
||||
<div class="bill-setting">
|
||||
<div class="button-container">
|
||||
<el-button type="primary" @click="addNewPayClick">新增账户</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
:data="billStore.billPayList"
|
||||
border stripe
|
||||
:header-cell-style="tableHeaderStyle()"
|
||||
:cell-style="tableCellStyle()"
|
||||
:row-style="tableRowStyle()"
|
||||
style="width: 100%"
|
||||
class="card-item">
|
||||
<el-table-column type="index" align="center" width="50" />
|
||||
<el-table-column prop="name" label="名称" align="center" width="100"/>
|
||||
<el-table-column label="图标" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<i :class="scope.row.icon" :style="{color: scope.row.color, fontSize: '24px'}"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" size="small" @click="editPayClick(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="small" @click="deletePayClick(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog v-model="billInfo.billPayDialog.visible"
|
||||
:title="billInfo.billPayDialog.title"
|
||||
center width="80%" @open="openDialogEvent">
|
||||
<el-form ref="formRef" :model="billInfo.billPayDialog.data"
|
||||
:rules="rules" label-position="top" label-width="100px">
|
||||
<el-form-item label="账户名称" prop="name">
|
||||
<el-input v-model="billInfo.billPayDialog.data.name" autocomplete="off"
|
||||
placeholder="请输入类型名称"
|
||||
:maxlength="10" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="账户图标" prop="icon">
|
||||
<el-input v-model="billInfo.billPayDialog.data.icon" autocomplete="off"
|
||||
placeholder="请输入类型图标"
|
||||
:maxlength="40" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标颜色" prop="color">
|
||||
<el-color-picker v-model="billInfo.billPayDialog.data.color" />
|
||||
</el-form-item>
|
||||
<el-form-item label="图标预览">
|
||||
<i :class="billInfo.billPayDialog.data.icon"
|
||||
:style="{color: billInfo.billPayDialog.data.color, fontSize: '24px'}"></i>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { useBillStore } from '@/store/bill'
|
||||
import { ElMessage, FormRules } from 'element-plus'
|
||||
import { IBillPay } from '@/types/bill'
|
||||
import { billPayRules } from '@/utils/element/elRules'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { addBillPayApi, updateBillPayApi } from '@/apis/bill'
|
||||
import { tableCellStyle, tableHeaderStyle, tableRowStyle } from 'vue3-common/utils/elUtil'
|
||||
import type { IDialog, IHandleApi } from 'vue3-common/types'
|
||||
|
||||
const formRef = ref()
|
||||
const rules = reactive<FormRules>(billPayRules)
|
||||
const billStore = useBillStore()
|
||||
|
||||
const billInfo = reactive({
|
||||
setBillPayType: 'ADD' as IHandleApi,
|
||||
billPayDialog: {
|
||||
title: '',
|
||||
visible: false,
|
||||
data: {}
|
||||
} as IDialog<IBillPay>
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await billStore.queryBillPay()
|
||||
})
|
||||
|
||||
/**
|
||||
* 点击新增账户按钮
|
||||
*/
|
||||
const addNewPayClick = () => {
|
||||
billInfo.setBillPayType = 'ADD'
|
||||
billInfo.billPayDialog = {
|
||||
title: '新增账户',
|
||||
visible: true,
|
||||
data: {
|
||||
name: '',
|
||||
icon: '',
|
||||
color: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击编辑账户按钮
|
||||
* @param pay 账户
|
||||
*/
|
||||
const editPayClick = async (pay: IBillPay) => {
|
||||
billInfo.setBillPayType = 'UPDATE'
|
||||
billInfo.billPayDialog = {
|
||||
title: '编辑账户',
|
||||
visible: true,
|
||||
data: deepCopyObject(pay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击删除账户按钮
|
||||
* @param pay 账户
|
||||
*/
|
||||
const deletePayClick = (pay: IBillPay) => {
|
||||
billInfo.setBillPayType = 'DELETE'
|
||||
ElMessage.error('暂不支持该功能')
|
||||
}
|
||||
|
||||
const openDialogEvent = () => {
|
||||
nextTick(() => {
|
||||
formRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
const setBillBookApi = async (id?: number) => {
|
||||
switch (billInfo.setBillPayType) {
|
||||
case 'ADD':
|
||||
await addBillPayApi(billInfo.billPayDialog.data)
|
||||
ElMessage.success('新增账户成功')
|
||||
break
|
||||
case 'UPDATE':
|
||||
await updateBillPayApi(id as number, billInfo.billPayDialog.data)
|
||||
ElMessage.success('更新账户成功')
|
||||
break
|
||||
case 'DELETE':
|
||||
ElMessage.success('删除账户成功')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
await billStore.queryBillPay()
|
||||
billInfo.billPayDialog.visible = false
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
billInfo.billPayDialog.visible = false
|
||||
}
|
||||
|
||||
const confirmClick = async () => {
|
||||
await formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
setBillBookApi(billInfo.billPayDialog.data.id)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<div class="budget-chart">
|
||||
<div class="budget-rank-chart card-item" ref="budgetRankChartRef"/>
|
||||
<div class="budget-project-chart card-item" ref="budgetProjectChartRef"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import { useBudgetStore } from '@/store/budget'
|
||||
import { barChartOptions, pieChartOptions } from 'vue3-common/utils/eChartsUtil'
|
||||
|
||||
const budgetStore = useBudgetStore()
|
||||
|
||||
const budgetRankChartRef = ref<HTMLElement>()
|
||||
const budgetProjectChartRef = ref<HTMLElement>()
|
||||
|
||||
let budgetRankChart: echarts.ECharts
|
||||
let budgetProjectChart: echarts.ECharts
|
||||
|
||||
watch(() => budgetStore.isRefresh, () => {
|
||||
updateChart()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
budgetRankChart = echarts.init(budgetRankChartRef.value as HTMLElement)
|
||||
budgetProjectChart = echarts.init(budgetProjectChartRef.value as HTMLElement)
|
||||
})
|
||||
|
||||
const updateChart = () => {
|
||||
// 预算排行统计图
|
||||
const rankNameList = budgetStore.budgetRankStatsList.map((item) => item.name)
|
||||
const rankValueList = budgetStore.budgetRankStatsList.map((item) => item.value)
|
||||
budgetRankChart.setOption(barChartOptions('📊预算排行', '项目', rankNameList, '金额', rankValueList))
|
||||
|
||||
// 预算项目统计图
|
||||
budgetProjectChart.setOption(pieChartOptions('📊预算项目', '项目', '', budgetStore.budgetProjectStatsList))
|
||||
}
|
||||
</script>
|
||||
@@ -1,114 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="budgetStore.budgetDialog.visible"
|
||||
:title="budgetStore.budgetDialog.title"
|
||||
center @open="openDialogEvent"
|
||||
width="50%" class="budget-dialog">
|
||||
<el-form ref="formRef" :model="budgetStore.budgetDialog.data"
|
||||
:rules="rules" label-width="100px">
|
||||
<el-form-item label="预算类别" prop="category">
|
||||
<el-select
|
||||
v-model="budgetStore.budgetDialog.data.category"
|
||||
allow-create filterable placeholder="请输入或选择预算类别">
|
||||
<el-option
|
||||
v-for="(item, index) in budgetStore.budgetCategoryList"
|
||||
:key="index" :label="item" :value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="预算项目" prop="project">
|
||||
<el-input v-model="budgetStore.budgetDialog.data.project" autocomplete="off"
|
||||
placeholder="请输入预算项目" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="预算内容" prop="content">
|
||||
<el-input v-model="budgetStore.budgetDialog.data.content" autocomplete="off"
|
||||
placeholder="请输入预算内容" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="供应商" prop="vendor">
|
||||
<el-input v-model="budgetStore.budgetDialog.data.vendor" autocomplete="off"
|
||||
placeholder="请输入预算供应商" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="预算支出" prop="budget">
|
||||
<el-input
|
||||
v-model="budgetStore.budgetDialog.data.budget"
|
||||
placeholder="请输入预算支出" clearable
|
||||
:formatter="(value: string) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
|
||||
:parser="(value: string) => value.replace(/\$\s?|(,*)/g, '')"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="实际支出" prop="actual">
|
||||
<el-input
|
||||
v-model="budgetStore.budgetDialog.data.actual"
|
||||
placeholder="请输入实际支出" clearable
|
||||
:formatter="(value: string) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
|
||||
:parser="(value: string) => value.replace(/\$\s?|(,*)/g, '')"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="支付时间">
|
||||
<el-date-picker
|
||||
v-model="budgetStore.budgetDialog.data.payTime"
|
||||
type="datetime" placeholder="请选择支付时间"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remake">
|
||||
<el-input v-model="budgetStore.budgetDialog.data.remake" autocomplete="off"
|
||||
placeholder="请输入备注" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useBudgetStore } from '@/store/budget'
|
||||
import { FormRules } from 'element-plus'
|
||||
import { budgetRules } from '@/utils/element/elRules'
|
||||
import { nextTick, reactive, ref } from 'vue'
|
||||
|
||||
const formRef = ref()
|
||||
const rules = reactive<FormRules>(budgetRules)
|
||||
const budgetStore = useBudgetStore()
|
||||
|
||||
/**
|
||||
* 打开对话框事件
|
||||
*/
|
||||
const openDialogEvent = async () => {
|
||||
await nextTick(() => {
|
||||
formRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击确认按钮
|
||||
*/
|
||||
const confirmClick = () => {
|
||||
formRef.value.validate().then(async () => {
|
||||
await budgetStore.handleBlogApi(budgetStore.budgetDialog.data.id)
|
||||
budgetStore.queryInfo.category = budgetStore.budgetDialog.data.category
|
||||
})
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
budgetStore.budgetDialog.visible = false
|
||||
}
|
||||
</script>
|
||||
@@ -1,54 +0,0 @@
|
||||
<template>
|
||||
<div class="budget-query common-query">
|
||||
<el-switch
|
||||
v-model="budgetStore.showDataType"
|
||||
inline-prompt
|
||||
style="--el-switch-on-color: #CA6C65; --el-switch-off-color: #009FA8"
|
||||
active-value="CHART" inactive-value="DATA"
|
||||
active-text="图表统计" inactive-text="数据显示"
|
||||
@change="changeShowDataTypeEvent"
|
||||
/>
|
||||
|
||||
<el-select
|
||||
v-model="budgetStore.queryInfo.category"
|
||||
placeholder="请选择类别" style="width: 120px"
|
||||
@focus="focusCategoryEvent" @change="changeCategoryEvent">
|
||||
<el-option
|
||||
v-for="(item, index) in budgetStore.budgetCategoryList"
|
||||
:key="index" :label="item" :value="item"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-button v-if="budgetStore.showDataType === 'DATA'"
|
||||
type="primary" @click="addBudgeClick">新增预算
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useBudgetStore } from '@/store/budget'
|
||||
|
||||
const budgetStore = useBudgetStore()
|
||||
|
||||
const focusCategoryEvent = async () => {
|
||||
await budgetStore.queryBudgetCategory()
|
||||
}
|
||||
|
||||
const changeCategoryEvent = async () => {
|
||||
await budgetStore.refreshInfo()
|
||||
}
|
||||
|
||||
const addBudgeClick = () => {
|
||||
budgetStore.budgetApiType = 'ADD'
|
||||
budgetStore.budgetDialog = {
|
||||
title: '新增预算',
|
||||
visible: true,
|
||||
data: budgetStore.getEmptyBudget()
|
||||
}
|
||||
budgetStore.budgetDialog.data.category = budgetStore.queryInfo.category
|
||||
}
|
||||
|
||||
const changeShowDataTypeEvent = async () => {
|
||||
await budgetStore.refreshInfo()
|
||||
}
|
||||
</script>
|
||||
@@ -1,98 +0,0 @@
|
||||
<template>
|
||||
<el-table :data="budgetStore.budgetList"
|
||||
border stripe show-summary
|
||||
:span-method="spanMethod" :summary-method="summaryMethod"
|
||||
:header-cell-style="tableHeaderStyle()"
|
||||
:row-style="tableRowStyle()" :cell-style="tableCellStyle()"
|
||||
class="budget-table card-item">
|
||||
<el-table-column type="index" align="center" width="80"/>
|
||||
<el-table-column prop="project" label="项目" align="center" min-width="5%"/>
|
||||
<el-table-column prop="content" label="内容" align="center" min-width="10%"/>
|
||||
<el-table-column prop="vendor" label="供应商" align="center" min-width="10%"/>
|
||||
<el-table-column prop="budget" label="预算支出(元)" align="center" min-width="10%">
|
||||
<template #default="scope">
|
||||
{{ formatAmount(scope.row.budget) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="actual" label="实际支出(元)" align="center" min-width="10%">
|
||||
<template #default="scope">
|
||||
{{ formatAmount(scope.row.actual) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="save" label="节省预算(元)" align="center" min-width="10%">
|
||||
<template #default="scope">
|
||||
{{ formatAmount(scope.row.budget - scope.row.actual) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="percent" label="支出占比" align="center" min-width="10%">
|
||||
<template #default="scope">
|
||||
{{ `${((scope.row.actual / totalActual) * 100).toFixed(2)}%` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remake" label="备注" align="center" min-width="10%"/>
|
||||
<el-table-column fixed="right" label="操作" align="center" width="250">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" @click="editBudget(scope.row)">编辑</el-button>
|
||||
<el-button type="primary" @click="editBudget(scope.row)">账单</el-button>
|
||||
<el-button type="danger" @click="deleteBudget(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useBudgetStore } from '@/store/budget'
|
||||
import { IBudgetInfo } from '@/types/budget.ts'
|
||||
import { computed } from 'vue'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { formatAmount } from 'vue3-common/utils/numberUtil'
|
||||
import { getRowspan, getSummaryData } from 'vue3-common/utils/elUtil'
|
||||
import { commonElMessageBox, tableHeaderStyle, tableCellStyle, tableRowStyle } from 'vue3-common/utils/elUtil'
|
||||
|
||||
const budgetStore = useBudgetStore()
|
||||
|
||||
const spanIndex = 1
|
||||
const summaryColumnList = ['budget', 'actual', 'save']
|
||||
|
||||
const totalActual = computed(() => {
|
||||
return budgetStore.budgetList.reduce((sum, item: IBudgetInfo) => {
|
||||
return sum + Number(item.actual || 0)
|
||||
}, 0)
|
||||
})
|
||||
|
||||
const spanMethod = (data: { row: any; column: any; rowIndex: number; columnIndex: number }) => {
|
||||
// 需要合并的列索引
|
||||
if (data.columnIndex === spanIndex) {
|
||||
return getRowspan(budgetStore.budgetList, data.column.property, data.rowIndex, data.row)
|
||||
}
|
||||
}
|
||||
|
||||
const summaryMethod = (data: { columns: any[]; data: any[] }) => {
|
||||
const sums = getSummaryData(data.columns, data.data, summaryColumnList)
|
||||
// 格式化输出
|
||||
sums[6] = formatAmount(parseFloat(sums[4] as string) - parseFloat(sums[5] as string))
|
||||
sums[4] = formatAmount(parseFloat(sums[4] as string))
|
||||
sums[5] = formatAmount(parseFloat(sums[5] as string))
|
||||
sums[7] = '100%'
|
||||
return sums
|
||||
}
|
||||
|
||||
const editBudget = (budget: IBudgetInfo) => {
|
||||
budgetStore.budgetApiType = 'UPDATE'
|
||||
budgetStore.budgetDialog = {
|
||||
title: '编辑预算',
|
||||
visible: true,
|
||||
data: deepCopyObject(budget)
|
||||
}
|
||||
}
|
||||
|
||||
const deleteBudget = (budget: IBudgetInfo) => {
|
||||
budgetStore.budgetApiType = 'DELETE'
|
||||
commonElMessageBox('是否删除该预算?').then(() => {
|
||||
budgetStore.handleBlogApi(budget.id as number)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,134 +0,0 @@
|
||||
<template>
|
||||
<div class="life-record-card card-item">
|
||||
<el-carousel v-if="props.foodItem?.recordList.length > 0"
|
||||
arrow="always" @change="changeFoodEvent">
|
||||
<el-carousel-item v-for="(item, index) in getFoodRecord(props.foodItem?.recordList)"
|
||||
:key="index">
|
||||
<el-image :src="serviceFileRootPath + item.imageUrl"
|
||||
fit="contain" alt="暂无成果">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<span>暂无图片</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
|
||||
<el-empty v-else description="暂无成果" />
|
||||
|
||||
<div class="record-info">
|
||||
<div class="top-container">
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<span class="title">{{ props.foodItem.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="button-info">
|
||||
<el-button v-if="!isMobile()"
|
||||
type="primary" :icon="Edit" circle :size="'small'"
|
||||
@click="editFoodRecipeClick"/>
|
||||
<el-button type="primary" :icon="MoreFilled" circle :size="'small'"
|
||||
@click="viewFoodRecipeClick()" />
|
||||
<el-button type="danger" :icon="DeleteFilled" circle :size="'small'"
|
||||
@click="deleteFoodRecipeClick()" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-container">
|
||||
<div class="info-list">
|
||||
<div class="info-item category-item">
|
||||
<i class="fa-solid fa-utensils"></i>
|
||||
{{ props.foodItem.category }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="props.foodItem?.recordList.length > 0" class="info-list">
|
||||
<div class="info-item">
|
||||
<i class="fa-solid fa-flag"></i>
|
||||
{{ props.foodItem.recordList[foodCardInfo.currentFoodIndex].person}}
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<i class="fa-regular fa-calendar-check"></i>
|
||||
{{ formatDate(props.foodItem.recordList[foodCardInfo.currentFoodIndex].date) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<span>暂无成果</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Edit, MoreFilled, DeleteFilled } from '@element-plus/icons-vue'
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { defineProps, onMounted, PropType, reactive } from 'vue'
|
||||
import { IFoodRecipe, IFoodRecord } from '@/types/food.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { formatDate } from 'vue3-common/utils/dateUtil'
|
||||
import { deepCopyObject } from 'vue3-common/utils/dataUtil'
|
||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||
import { serviceFileRootPath } from '@/utils'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
|
||||
const router = useRouter()
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
const foodCardInfo = reactive({
|
||||
recommendRate: 0,
|
||||
currentFoodIndex: 0
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
foodItem: {
|
||||
required: true,
|
||||
type: Object as PropType<IFoodRecipe>
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
foodCardInfo.recommendRate = props.foodItem?.recommendRate as number
|
||||
})
|
||||
|
||||
const getFoodRecord = (recordList: IFoodRecord[]) => {
|
||||
return recordList.filter((item) => item.imageUrl)
|
||||
}
|
||||
|
||||
const editFoodRecipeClick = async () => {
|
||||
const id = props.foodItem?.id
|
||||
foodStore.foodRecipeApiType = 'UPDATE'
|
||||
await foodStore.queryFoodRecipe(id as number)
|
||||
foodStore.foodRecipeDialog = {
|
||||
title: '编辑菜谱',
|
||||
visible: true,
|
||||
data: deepCopyObject(foodStore.currentFoodRecipe)
|
||||
}
|
||||
}
|
||||
|
||||
const viewFoodRecipeClick = async () => {
|
||||
if (isMobile()) {
|
||||
await router.push({ name: 'MobileHomeFoodDetailId', params: { id: props.foodItem?.id } })
|
||||
} else {
|
||||
await router.push({ name: 'HomeLifeFoodId', params: { id: props.foodItem?.id } })
|
||||
}
|
||||
}
|
||||
|
||||
const deleteFoodRecipeClick = () => {
|
||||
foodStore.foodRecipeApiType = 'DELETE'
|
||||
commonElMessageBox(`请确认是否删除该菜谱: ${props.foodItem?.name}?`).then(() => {
|
||||
foodStore.handleFoodRecipeApi(props.foodItem?.id as number)
|
||||
})
|
||||
}
|
||||
|
||||
const changeFoodEvent = (current: number) => {
|
||||
foodCardInfo.currentFoodIndex = current
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/styles/home/life.record.module.scss";
|
||||
</style>
|
||||
@@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<div class="food-daily-list">
|
||||
<el-date-picker v-model="foodStore.queryRecord.year"
|
||||
type="year" :editable="false" style="width: 120px;"
|
||||
@change="foodStore.refreshInfo()"/>
|
||||
|
||||
<el-empty v-if="foodDailyInfo.dateList.length === 0"/>
|
||||
|
||||
<el-scrollbar>
|
||||
<food-daily-item v-for="(item, index) in foodDailyInfo.dateList"
|
||||
:key="index" :date="item"/>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FoodDailyItem from '@/components/Home/Food/FoodDailyItem.vue'
|
||||
import { reactive, watch } from 'vue'
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
watch(() => foodStore.isRefresh, () => {
|
||||
updateInfo()
|
||||
})
|
||||
|
||||
const foodDailyInfo = reactive({
|
||||
dateList: [] as string[]
|
||||
})
|
||||
|
||||
const updateInfo = () => {
|
||||
const dateList = foodStore.foodRecordList.map((item) => item.date)
|
||||
foodDailyInfo.dateList = [...new Set(dateList)] as string[]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.food-daily-list {
|
||||
height: calc(100vh - 120px);
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1vh;
|
||||
|
||||
.el-date-editor {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
.el-scrollbar__view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,116 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="dialogData.visible" :title="dialogData.title"
|
||||
center @open="openDialogEvent" class="food-dialog">
|
||||
<el-form ref="formRef" :model="dialogData.data"
|
||||
:rules=rules label-width="80px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="美食名称" prop="name">
|
||||
<el-input v-model="dialogData.data.name" autocomplete="off"
|
||||
placeholder="请输入美食名称" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="美食菜系" prop="category">
|
||||
<el-select v-model="dialogData.data.category">
|
||||
<el-option v-for="(item, index) in foodCategoryList"
|
||||
:key="index" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="推荐指数" prop="recommendRate">
|
||||
<el-rate v-model="dialogData.data.recommendRate"
|
||||
:colors="foodStore.rateColorList"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="食材">
|
||||
<food-material-form />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="步骤">
|
||||
<food-step-form />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="dialogData.data.remark" autocomplete="off"
|
||||
placeholder="请输入备注" clearable
|
||||
show-word-limit maxlength="20">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">保存</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import FoodMaterialForm from '@/components/Home/Food/Form/FoodMaterialForm.vue'
|
||||
import FoodStepForm from '@/components/Home/Food/Form/FoodStepForm.vue'
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { FormInstance, FormRules } from 'element-plus'
|
||||
import { computed, nextTick, ref, reactive } from 'vue'
|
||||
import { foodRules } from '@/utils/element/elRules'
|
||||
|
||||
const rules = reactive<FormRules>(foodRules)
|
||||
const formRef = ref<FormInstance>()
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
const foodCategoryList = ['家常菜', '淮扬菜', '鲁菜', '川菜', '粤菜', '闽菜', '浙菜', '湘菜', '徽菜', '其他']
|
||||
|
||||
const dialogData = computed(() => foodStore.foodRecipeDialog)
|
||||
|
||||
/**
|
||||
* 打开对话框事件
|
||||
*/
|
||||
const openDialogEvent = async () => {
|
||||
await nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 点击确认按钮
|
||||
*/
|
||||
const confirmClick = () => {
|
||||
formRef.value?.validate().then(() => {
|
||||
foodStore.handleFoodRecipeApi()
|
||||
})
|
||||
}
|
||||
|
||||
const cancelClick = () => {
|
||||
dialogData.value.visible = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.food-dialog {
|
||||
width: 75%;
|
||||
|
||||
.el-dialog__body {
|
||||
height: 65vh;
|
||||
|
||||
.el-button.is-text {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.material-table {
|
||||
height: 45vh;
|
||||
}
|
||||
|
||||
.food-step-table {
|
||||
height: 55vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,68 +0,0 @@
|
||||
<template>
|
||||
<div v-if="isMobile()" class="mobile-common-query card-item">
|
||||
<div class="query-item">
|
||||
<span>分类:</span>
|
||||
<el-segmented v-model="foodStore.queryRecipe.category"
|
||||
:options="queryCategoryList"
|
||||
@change="queryFoodSegmented"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="common-query">
|
||||
<el-select v-model="foodStore.queryDateType"
|
||||
@change="foodStore.refreshInfo()"
|
||||
style="width: 120px;align-self: center;">
|
||||
<el-option v-for="(item, index) in dateTypeOptions" :key="index"
|
||||
:label="item.label" :value="item.value"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { ICategory } from '@/types'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
const queryCategoryList = ref([] as ICategory[])
|
||||
|
||||
onMounted(async () => {
|
||||
await foodStore.queryFoodCategory()
|
||||
initCategoryList()
|
||||
})
|
||||
|
||||
const dateTypeOptions = [{
|
||||
label: '按月选择',
|
||||
value: 'month'
|
||||
},
|
||||
{
|
||||
label: '按年选择',
|
||||
value: 'year'
|
||||
}]
|
||||
|
||||
const initCategoryList = () => {
|
||||
queryCategoryList.value = []
|
||||
queryCategoryList.value.push({
|
||||
label: '全部',
|
||||
value: ''
|
||||
})
|
||||
foodStore.foodCategoryList.forEach((item) => {
|
||||
queryCategoryList.value.push({
|
||||
label: item,
|
||||
value: item
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const queryFoodSegmented = async () => {
|
||||
foodStore.pageInfo = {
|
||||
currentPage: 1,
|
||||
pageSize: 3,
|
||||
totalSize: 1
|
||||
}
|
||||
foodStore.foodRecipeList = []
|
||||
await foodStore.queryMobileFoodRecipeList()
|
||||
}
|
||||
</script>
|
||||
@@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<div class="food-list card-item">
|
||||
<el-empty v-if="foodStore.foodRecipeList.length === 0" description="暂无美食记录"/>
|
||||
|
||||
<div v-else class="list">
|
||||
<food-card v-for="(item, index) in foodStore.foodRecipeList"
|
||||
:key="index" :food-item="item"/>
|
||||
</div>
|
||||
|
||||
<el-pagination
|
||||
v-model:current-page="foodStore.pageInfo.currentPage"
|
||||
:page-size="foodStore.pageInfo.pageSize"
|
||||
layout="total, prev, pager, next"
|
||||
:total="foodStore.pageInfo.totalSize"
|
||||
@change="changePageEvent"
|
||||
/>
|
||||
|
||||
<el-button v-if="isLargeScreen()"
|
||||
type="primary" :icon="Plus" circle
|
||||
@click="addFoodRecipeClick" class="add-new" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import FoodCard from '@/components/Home/Food/FoodCard.vue'
|
||||
import { useFoodStore } from '@/store/food.ts'
|
||||
import { isLargeScreen } from '@/utils'
|
||||
|
||||
const foodStore = useFoodStore()
|
||||
|
||||
const addFoodRecipeClick = () => {
|
||||
foodStore.foodRecipeApiType = 'ADD'
|
||||
foodStore.foodRecipeDialog = {
|
||||
title: '新增菜谱',
|
||||
visible: true,
|
||||
data: foodStore.getEmptyFoodRecipe()
|
||||
}
|
||||
}
|
||||
|
||||
const changePageEvent = (value: number) => {
|
||||
foodStore.pageInfo.currentPage = value
|
||||
foodStore.queryFoodRecipeList()
|
||||
}
|
||||
</script>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user