├── .gitignore
├── Readme.md
├── doc
└── python_job.docx
├── server
├── manage.py
├── myapp
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── auth
│ │ ├── __init__.py
│ │ └── authentication.py
│ ├── handler.py
│ ├── middlewares
│ │ ├── LogMiddleware.py
│ │ └── __init__.py
│ ├── models.py
│ ├── permission
│ │ ├── __init__.py
│ │ └── permission.py
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ ├── utils.py
│ └── views
│ │ ├── __init__.py
│ │ └── index
│ │ ├── __init__.py
│ │ ├── address.py
│ │ ├── classification.py
│ │ ├── comment.py
│ │ ├── company.py
│ │ ├── notice.py
│ │ ├── order.py
│ │ ├── post.py
│ │ ├── resume.py
│ │ ├── tag.py
│ │ ├── thing.py
│ │ └── user.py
├── readme.md
├── requirements.txt
├── server
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── upload
│ ├── company
│ ├── 1685770491227.png
│ ├── 1685770768426.jpeg
│ ├── 1685771081809.png
│ └── 1685848419951.png
│ ├── cover
│ └── 1.jpeg
│ ├── img
│ ├── Wechat.jpeg
│ ├── a.png
│ ├── b.png
│ └── weixin.png
│ ├── raw
│ └── 1685780971830.jpeg
│ └── resume
│ ├── 1685772029168.png
│ ├── 1685772036385.jpeg
│ ├── 1685772067199.jpeg
│ ├── logo.png
│ └── logo_Yvy8kmb.png
└── web
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .stylelintignore
├── README.md
├── build
├── constant.ts
└── vite
│ └── plugins
│ ├── autoImport.ts
│ ├── component.ts
│ ├── compress.ts
│ ├── imagemin.ts
│ ├── index.ts
│ ├── progress.ts
│ ├── restart.ts
│ ├── unocss.ts
│ └── visualizer.ts
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── prettier.config.js
├── public
├── favicon.ico
└── images
│ ├── admin-login-bg.jpg
│ ├── bg2.jpg
│ └── demo.jpg
├── src
├── App.vue
├── api
│ ├── admin
│ │ ├── ad.ts
│ │ ├── classification.ts
│ │ ├── comment.ts
│ │ ├── company.ts
│ │ ├── log.ts
│ │ ├── notice.ts
│ │ ├── order.ts
│ │ ├── overview.ts
│ │ ├── resume.ts
│ │ ├── tag.ts
│ │ ├── thing.ts
│ │ └── user.ts
│ └── index
│ │ ├── address.ts
│ │ ├── classification.ts
│ │ ├── comment.ts
│ │ ├── company.ts
│ │ ├── notice.ts
│ │ ├── order.ts
│ │ ├── post.ts
│ │ ├── resume.ts
│ │ ├── tag.ts
│ │ ├── thing.ts
│ │ ├── thingCollect.ts
│ │ ├── thingWish.ts
│ │ └── user.ts
├── assets
│ ├── fonts
│ │ ├── Blimone-ExtraBold.woff
│ │ ├── Blimone-ExtraLight.woff
│ │ ├── Blimone-Light.woff
│ │ └── Blimone-Regular.woff
│ ├── icons
│ │ ├── logo.png
│ │ └── svg
│ │ │ ├── github.svg
│ │ │ ├── logo.svg
│ │ │ ├── marks.svg
│ │ │ ├── test.svg
│ │ │ ├── ts.svg
│ │ │ └── twitter.svg
│ ├── images
│ │ ├── add.svg
│ │ ├── address-right-icon.svg
│ │ ├── ali-pay-icon.svg
│ │ ├── avatar.jpg
│ │ ├── banner-02.webp
│ │ ├── banner2.svg
│ │ ├── cart-icon.svg
│ │ ├── clear-search.svg
│ │ ├── code-icon.svg
│ │ ├── delete-icon.svg
│ │ ├── ebook-download-icon.svg
│ │ ├── ic-company.png
│ │ ├── k-logo.png
│ │ ├── login-banner.png
│ │ ├── login.png
│ │ ├── logo.png
│ │ ├── mail-icon.svg
│ │ ├── message-icon.svg
│ │ ├── order-address-icon.svg
│ │ ├── order-icon.svg
│ │ ├── order-point-icon.svg
│ │ ├── order-thing-icon.svg
│ │ ├── pwd-hidden.svg
│ │ ├── pwd-icon.svg
│ │ ├── qunerweima.jpg
│ │ ├── read-online-icon.svg
│ │ ├── recommend-hover.svg
│ │ ├── register-name.svg
│ │ ├── search-icon.svg
│ │ ├── searchIcon.svg
│ │ ├── setting-card-icon.svg
│ │ ├── setting-icon.svg
│ │ ├── setting-msg-icon.svg
│ │ ├── setting-push-icon.svg
│ │ ├── setting-safe-icon.svg
│ │ ├── share-icon.svg
│ │ ├── tel-icon.svg
│ │ ├── want-read-hover.svg
│ │ ├── wb-share.svg
│ │ └── wx-pay-icon.svg
│ └── styles
│ │ └── base.less
├── core
│ └── bootstrap.js
├── main.ts
├── router
│ ├── index.ts
│ └── root.ts
├── store
│ ├── constants.ts
│ ├── index.ts
│ └── modules
│ │ ├── app
│ │ ├── index.ts
│ │ └── types.ts
│ │ └── user
│ │ ├── index.ts
│ │ └── types.ts
├── styles
│ ├── index.less
│ └── reset.less
├── utils
│ ├── auth.ts
│ ├── http
│ │ └── axios
│ │ │ ├── index.ts
│ │ │ ├── status.ts
│ │ │ └── type.ts
│ ├── index.ts
│ └── result.ts
└── views
│ └── index
│ ├── components
│ ├── content.vue
│ ├── footer.vue
│ ├── header.vue
│ └── search-content-view.vue
│ ├── confirm.vue
│ ├── detail.vue
│ ├── index.vue
│ ├── login.vue
│ ├── pay.vue
│ ├── portal.vue
│ ├── register.vue
│ ├── search.vue
│ ├── user
│ ├── address-view.vue
│ ├── collect-thing-view.vue
│ ├── comment-view.vue
│ ├── company-edit-view.vue
│ ├── company-post-view.vue
│ ├── fans-view.vue
│ ├── follow-view.vue
│ ├── message-view.vue
│ ├── mine-infos-view.vue
│ ├── modal
│ │ └── edit-address.vue
│ ├── my-post-view.vue
│ ├── my-thing-view.vue
│ ├── order-view.vue
│ ├── push-view.vue
│ ├── resume-edit-view.vue
│ ├── score-view.vue
│ ├── security-view.vue
│ ├── userinfo-edit-view.vue
│ └── wish-thing-view.vue
│ └── usercenter.vue
├── stylelint.config.js
├── tsconfig.json
├── types
├── auto-imports.d.ts
├── components.d.ts
└── env.d.ts
├── vite.config.ts
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | /server/myapp/migrations
2 | /server/myapp/views/__pycache__/
3 | /server/.idea
4 | /web/.idea
5 | /web/dist
6 | /web/node_modules
7 | /server/.idea/
8 | /.idea/
9 | __pycache__
10 | .idea
11 | server/.idea
12 | .DS_Store
13 | server/.DS_Store
14 | web/.DS_Store
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | > 学习过程中,遇到问题可以咨询作者
2 |
3 |
4 | ### 演示地址
5 |
6 | 前台地址: http://job.gitapp.cn
7 |
8 | 后台地址:http://job.gitapp.cn/admin
9 |
10 | 后台管理帐号:
11 |
12 | 用户名:admin123
13 | 密码:admin123
14 |
15 |
16 | ### 功能介绍
17 |
18 | 平台采用B/S结构,后端采用主流的Python语言进行开发,前端采用主流的Vue.js进行开发。
19 |
20 | 整个平台包括前台和后台两个部分。
21 |
22 | - 前台功能包括:首页、岗位详情页、简历中心、用户设置模块。
23 | - 后台功能包括:总览、岗位管理、公司管理、分类管理、标签管理、评论管理、用户管理、运营管理、日志管理、系统信息模块。
24 |
25 |
26 | ### 代码结构
27 |
28 | - server目录是后端代码
29 | - web目录是前端代码
30 |
31 | ### 部署运行
32 |
33 | #### 后端运行步骤
34 |
35 | (1) 安装python 3.8
36 |
37 | (2) 安装依赖。进入server目录下,执行 pip install -r requirements.txt
38 |
39 | (3) 安装mysql 5.7数据库,并创建数据库,创建SQL如下:
40 | ```
41 | CREATE DATABASE IF NOT EXISTS xxx DEFAULT CHARSET utf8 COLLATE utf8_general_ci
42 | ```
43 | (4) 恢复sql数据。在mysql下依次执行如下命令:
44 |
45 | ```
46 | mysql> use xxx;
47 | mysql> source D:/xxx/xxx/xxx.sql;
48 | ```
49 |
50 | (5) 启动django服务。在server目录下执行:
51 | ```
52 | python manage.py runserver
53 | ```
54 |
55 | #### 前端运行步骤
56 |
57 | (1) 安装node 16.14
58 |
59 | (2) 进入web目录下,安装依赖,执行:
60 | ```
61 | npm install
62 | ```
63 | (3) 运行项目
64 | ```
65 | npm run dev
66 | ```
67 |
68 |
69 | ### 界面预览
70 |
71 | 首页
72 |
73 | 
74 |
75 |
76 | 后台页面
77 |
78 | 
79 |
80 |
81 |
82 |
83 | ### 参考论文
84 |
85 | [点击查看](doc/python_job.docx)
86 |
87 |
88 |
89 | ### 付费咨询
90 |
91 | 微信:lengqin1024
92 |
93 |
94 |
--------------------------------------------------------------------------------
/doc/python_job.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/doc/python_job.docx
--------------------------------------------------------------------------------
/server/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/server/myapp/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/myapp/__init__.py
--------------------------------------------------------------------------------
/server/myapp/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 | from myapp.models import Classification, Thing, Tag, User, Comment
5 |
6 | admin.site.register(Classification)
7 | admin.site.register(Tag)
8 | admin.site.register(Thing)
9 | admin.site.register(User)
10 | admin.site.register(Comment)
11 |
--------------------------------------------------------------------------------
/server/myapp/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class MyappConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'myapp'
7 |
--------------------------------------------------------------------------------
/server/myapp/auth/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/myapp/auth/__init__.py
--------------------------------------------------------------------------------
/server/myapp/auth/authentication.py:
--------------------------------------------------------------------------------
1 | from rest_framework import exceptions
2 | from rest_framework.authentication import BaseAuthentication
3 |
4 | from myapp.models import User
5 |
6 |
7 | # 后台接口认证
8 | class AdminTokenAuthtication(BaseAuthentication):
9 | def authenticate(self, request):
10 | adminToken = request.META.get("HTTP_ADMINTOKEN")
11 | print("检查adminToken==>" + adminToken)
12 | users = User.objects.filter(admin_token=adminToken)
13 | """
14 | 判定条件:
15 | 1. 传了adminToken
16 | 2. 查到了该帐号
17 | 3. 该帐号是管理员或演示帐号
18 | """
19 |
20 | if not adminToken or len(users) == 0 or users[0].role == '2':
21 | raise exceptions.AuthenticationFailed("AUTH_FAIL_END")
22 | else:
23 | print('adminToken验证通过')
24 |
25 |
26 | # 前台接口认证
27 | class TokenAuthtication(BaseAuthentication):
28 | def authenticate(self, request):
29 | token = request.META.get("HTTP_TOKEN", "")
30 | if token is not None:
31 | print("检查token==>" + token)
32 | users = User.objects.filter(token=token)
33 | # print(users)
34 | """
35 | 判定条件:
36 | 1. 传了token
37 | 2. 查到了该帐号
38 | 3. 该帐号是普通用户
39 | """
40 | if not token or len(users) == 0 or (users[0].role in ['1', '3']):
41 | raise exceptions.AuthenticationFailed("AUTH_FAIL_FRONT")
42 | else:
43 | print('token验证通过')
44 | else:
45 | print("检查token==>token 为空")
46 | raise exceptions.AuthenticationFailed("AUTH_FAIL_FRONT")
47 |
--------------------------------------------------------------------------------
/server/myapp/handler.py:
--------------------------------------------------------------------------------
1 | from rest_framework.response import Response
2 |
3 |
4 | class APIResponse(Response):
5 | def __init__(self, code=0, msg='', data=None, status=200, headers=None, content_type=None, **kwargs):
6 | dic = {'code': code, 'msg': msg}
7 | if data is not None:
8 | dic['data'] = data
9 |
10 | dic.update(kwargs) # 这里使用update
11 | super().__init__(data=dic, status=status,
12 | template_name=None, headers=headers,
13 | exception=False, content_type=content_type)
14 |
--------------------------------------------------------------------------------
/server/myapp/middlewares/LogMiddleware.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import time
3 | import json
4 |
5 | from django.utils.deprecation import MiddlewareMixin
6 |
7 | from myapp import utils
8 | from myapp.serializers import OpLogSerializer
9 |
10 |
11 | class OpLogs(MiddlewareMixin):
12 |
13 | def __init__(self, *args):
14 | super(OpLogs, self).__init__(*args)
15 |
16 | self.start_time = None # 开始时间
17 | self.end_time = None # 响应时间
18 | self.data = {} # dict数据
19 |
20 | def process_request(self, request):
21 |
22 | self.start_time = time.time() # 开始时间
23 |
24 | re_ip = utils.get_ip(request)
25 | re_method = request.method
26 | re_content = request.GET if re_method == 'GET' else request.POST
27 | if re_content:
28 | re_content = json.dumps(re_content)
29 | else:
30 | re_content = None
31 |
32 | self.data.update(
33 | {
34 | 're_url': request.path,
35 | 're_method': re_method,
36 | 're_ip': re_ip,
37 | # 're_content': re_content,
38 | }
39 | )
40 | # print(self.data)
41 |
42 | def process_response(self, request, response):
43 |
44 | # 耗时毫秒/ms
45 | self.end_time = time.time() # 响应时间
46 | access_time = self.end_time - self.start_time
47 | self.data['access_time'] = round(access_time * 1000)
48 |
49 | # 入库
50 | serializer = OpLogSerializer(data=self.data)
51 | if serializer.is_valid():
52 | serializer.save()
53 |
54 | return response
55 |
--------------------------------------------------------------------------------
/server/myapp/middlewares/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/myapp/middlewares/__init__.py
--------------------------------------------------------------------------------
/server/myapp/permission/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/myapp/permission/__init__.py
--------------------------------------------------------------------------------
/server/myapp/permission/permission.py:
--------------------------------------------------------------------------------
1 | from myapp.models import User
2 |
3 |
4 | def isDemoAdminUser(request):
5 | adminToken = request.META.get("HTTP_ADMINTOKEN")
6 | users = User.objects.filter(admin_token=adminToken)
7 | if len(users) > 0:
8 | user = users[0]
9 | if user.role == '3': # (角色3)表示演示帐号
10 | print('演示帐号===>')
11 | return True
12 | return False
13 |
--------------------------------------------------------------------------------
/server/myapp/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/server/myapp/utils.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import hashlib
3 | import time
4 |
5 | from rest_framework.views import exception_handler
6 |
7 | from myapp.serializers import ErrorLogSerializer
8 |
9 | def get_timestamp():
10 | return int(round(time.time() * 1000))
11 |
12 | def md5value(key):
13 | input_name = hashlib.md5()
14 | input_name.update(key.encode("utf-8"))
15 | md5str = (input_name.hexdigest()).lower()
16 | print('计算md5:', md5str)
17 | return md5str
18 |
19 |
20 | def dict_fetchall(cursor): # cursor是执行sql_str后的记录,作入参
21 | columns = [col[0] for col in cursor.description] # 得到域的名字col[0],组成List
22 | return [
23 | dict(zip(columns, row)) for row in cursor.fetchall()
24 | ]
25 |
26 |
27 | def get_ip(request):
28 | """
29 | 获取请求者的IP信息
30 | """
31 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
32 | if x_forwarded_for:
33 | ip = x_forwarded_for.split(',')[0]
34 | else:
35 | ip = request.META.get('REMOTE_ADDR')
36 | return ip
37 |
38 |
39 | def get_ua(request):
40 | """
41 | 获取请求者的IP信息
42 | """
43 | ua = request.META.get('HTTP_USER_AGENT')
44 | return ua[0:200]
45 |
46 |
47 | def getWeekDays():
48 | """
49 | 获取近一周的日期
50 | """
51 | week_days = []
52 | now = datetime.datetime.now()
53 | for i in range(7):
54 | day = now - datetime.timedelta(days=i)
55 | week_days.append(day.strftime('%Y-%m-%d %H:%M:%S.%f')[:10])
56 | week_days.reverse() # 逆序
57 | return week_days
58 |
59 |
60 | def get_monday():
61 | """
62 | 获取本周周一日期
63 | """
64 | now = datetime.datetime.now()
65 | monday = now - datetime.timedelta(now.weekday())
66 | return monday.strftime('%Y-%m-%d %H:%M:%S.%f')[:10]
67 |
68 |
69 | def log_error(request, content):
70 | """
71 | 记录错误日志
72 | """
73 | ip = get_ip(request)
74 | method = request.method
75 | url = request.path
76 |
77 | data = {
78 | 'ip': ip,
79 | 'method': method,
80 | 'url': url,
81 | 'content': content
82 | }
83 |
84 | # 入库
85 | serializer = ErrorLogSerializer(data=data)
86 | if serializer.is_valid():
87 | serializer.save()
88 |
--------------------------------------------------------------------------------
/server/myapp/views/__init__.py:
--------------------------------------------------------------------------------
1 | from myapp.views.admin import *
2 | from myapp.views.index import *
3 |
--------------------------------------------------------------------------------
/server/myapp/views/index/__init__.py:
--------------------------------------------------------------------------------
1 | from myapp.views.index.classification import *
2 | from myapp.views.index.tag import *
3 | from myapp.views.index.user import *
4 | from myapp.views.index.thing import *
5 | from myapp.views.index.resume import *
6 | from myapp.views.index.post import *
7 | from myapp.views.index.company import *
8 | from myapp.views.index.comment import *
9 | from myapp.views.index.order import *
10 | from myapp.views.index.notice import *
11 | from myapp.views.index.address import *
12 |
--------------------------------------------------------------------------------
/server/myapp/views/index/address.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from rest_framework.decorators import api_view, authentication_classes
3 |
4 | from myapp import utils
5 | from myapp.auth.authentication import TokenAuthtication
6 | from myapp.handler import APIResponse
7 | from myapp.models import Address
8 | from myapp.serializers import AddressSerializer
9 |
10 |
11 | @api_view(['GET'])
12 | def list_api(request):
13 | if request.method == 'GET':
14 | userId = request.GET.get('userId', -1)
15 |
16 | if userId != -1:
17 | addresses = Address.objects.filter(user=userId).order_by('-create_time')
18 | serializer = AddressSerializer(addresses, many=True)
19 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
20 | else:
21 | return APIResponse(code=1, msg='userId不能为空')
22 |
23 |
24 | @api_view(['POST'])
25 | @authentication_classes([TokenAuthtication])
26 | def create(request):
27 |
28 | address_content = request.POST.get('desc', None)
29 | user = request.POST.get('user', None)
30 | default = request.POST.get('default', False)
31 |
32 | if address_content is None or user is None:
33 | return APIResponse(code=1, msg='不能为空')
34 |
35 | if default:
36 | # 其他置为false
37 | Address.objects.filter(user=user).update(default=False)
38 |
39 | serializer = AddressSerializer(data=request.data)
40 | if serializer.is_valid():
41 | serializer.save()
42 | return APIResponse(code=0, msg='创建成功', data=serializer.data)
43 | else:
44 | utils.log_error(request, '参数错误')
45 |
46 | return APIResponse(code=1, msg='创建失败')
47 |
48 |
49 | @api_view(['POST'])
50 | @authentication_classes([TokenAuthtication])
51 | def update(request):
52 |
53 | try:
54 | pk = request.GET.get('id', -1)
55 | addresses = Address.objects.get(pk=pk)
56 | except Address.DoesNotExist:
57 | return APIResponse(code=1, msg='对象不存在')
58 |
59 | user = request.data['user']
60 | default = request.data['default']
61 |
62 | if default:
63 | # 其他置为false
64 | Address.objects.filter(user=user).update(default=False)
65 |
66 | serializer = AddressSerializer(addresses, data=request.data)
67 | if serializer.is_valid():
68 | serializer.save()
69 | return APIResponse(code=0, msg='更新成功', data=serializer.data)
70 | else:
71 | utils.log_error(request, '参数错误')
72 |
73 | return APIResponse(code=1, msg='更新失败')
74 |
75 |
76 | @api_view(['POST'])
77 | @authentication_classes([TokenAuthtication])
78 | def delete(request):
79 |
80 | try:
81 | ids = request.GET.get('ids')
82 | ids_arr = ids.split(',')
83 | Address.objects.filter(id__in=ids_arr).delete()
84 | except Address.DoesNotExist:
85 | return APIResponse(code=1, msg='对象不存在')
86 |
87 | return APIResponse(code=0, msg='删除成功')
88 |
--------------------------------------------------------------------------------
/server/myapp/views/index/classification.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from django.db import connection
3 | from rest_framework.decorators import api_view
4 |
5 | from myapp.handler import APIResponse
6 | from myapp.models import Classification
7 | from myapp.serializers import ClassificationSerializer
8 | from myapp.utils import dict_fetchall
9 |
10 |
11 | @api_view(['GET'])
12 | def list_api(request):
13 | if request.method == 'GET':
14 | classifications = Classification.objects.all().order_by('-create_time')
15 | serializer = ClassificationSerializer(classifications, many=True)
16 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/server/myapp/views/index/comment.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from rest_framework.decorators import api_view, authentication_classes
3 |
4 | from myapp.auth.authentication import AdminTokenAuthtication
5 | from myapp.handler import APIResponse
6 | from myapp.models import Comment
7 | from myapp.permission.permission import isDemoAdminUser
8 | from myapp.serializers import CommentSerializer
9 |
10 |
11 | @api_view(['GET'])
12 | def list_api(request):
13 | if request.method == 'GET':
14 | thingId = request.GET.get("thingId", None)
15 | order = request.GET.get("order", 'recent')
16 |
17 | if thingId:
18 | if order == 'recent':
19 | orderBy = '-comment_time'
20 | else:
21 | orderBy = '-like_count'
22 |
23 | comments = Comment.objects.select_related("thing").filter(thing=thingId).order_by(orderBy)
24 | # print(comments)
25 | serializer = CommentSerializer(comments, many=True)
26 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
27 | else:
28 | return APIResponse(code=1, msg='thingId不能为空')
29 |
30 | @api_view(['GET'])
31 | def list_my_comment(request):
32 | if request.method == 'GET':
33 | userId = request.GET.get("userId", None)
34 | order = request.GET.get("order", 'recent')
35 |
36 | if userId:
37 | if order == 'recent':
38 | orderBy = '-comment_time'
39 | else:
40 | orderBy = '-like_count'
41 |
42 | comments = Comment.objects.select_related("thing").filter(user=userId).order_by(orderBy)
43 | # print(comments)
44 | serializer = CommentSerializer(comments, many=True)
45 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
46 | else:
47 | return APIResponse(code=1, msg='userId不能为空')
48 |
49 | @api_view(['POST'])
50 | def create(request):
51 | serializer = CommentSerializer(data=request.data)
52 | if serializer.is_valid():
53 | serializer.save()
54 | return APIResponse(code=0, msg='创建成功', data=serializer.data)
55 | else:
56 | print(serializer.errors)
57 |
58 | return APIResponse(code=1, msg='创建失败')
59 |
60 |
61 | @api_view(['POST'])
62 | def delete(request):
63 | try:
64 | ids = request.GET.get('ids')
65 | ids_arr = ids.split(',')
66 | Comment.objects.filter(id__in=ids_arr).delete()
67 | except Comment.DoesNotExist:
68 | return APIResponse(code=1, msg='对象不存在')
69 |
70 | return APIResponse(code=0, msg='删除成功')
71 |
72 |
73 | @api_view(['POST'])
74 | def like(request):
75 | try:
76 | commentId = request.GET.get('commentId')
77 | comment = Comment.objects.get(pk=commentId)
78 | comment.like_count += 1
79 | comment.save()
80 | except Comment.DoesNotExist:
81 | return APIResponse(code=1, msg='对象不存在')
82 |
83 | return APIResponse(code=0, msg='推荐成功')
84 |
--------------------------------------------------------------------------------
/server/myapp/views/index/company.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from rest_framework.decorators import api_view, authentication_classes
3 |
4 | from myapp import utils
5 | from myapp.auth.authentication import AdminTokenAuthtication
6 | from myapp.handler import APIResponse
7 | from myapp.models import Classification, Thing, Tag, Company
8 | from myapp.permission.permission import isDemoAdminUser
9 | from myapp.serializers import ThingSerializer, UpdateThingSerializer, CompanySerializer
10 |
11 |
12 | @api_view(['GET'])
13 | def list_user_company_api(request):
14 | if request.method == 'GET':
15 | userId = request.GET.get('userId', None)
16 | if userId:
17 | companies = Company.objects.filter(user=userId)
18 | serializer = CompanySerializer(companies, many=True)
19 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
20 |
21 |
22 | @api_view(['POST'])
23 | def create(request):
24 |
25 | companies = Company.objects.filter(user=request.data['user'])
26 | if companies and len(companies) > 0:
27 | return APIResponse(code=1, msg='已创建过了')
28 |
29 | serializer = CompanySerializer(data=request.data)
30 | if serializer.is_valid():
31 | serializer.save()
32 | return APIResponse(code=0, msg='创建成功', data=serializer.data)
33 | else:
34 | print(serializer.errors)
35 | utils.log_error(request, '参数错误')
36 |
37 | return APIResponse(code=1, msg='创建失败')
38 |
39 |
40 | @api_view(['POST'])
41 | def update(request):
42 |
43 | try:
44 | pk = request.GET.get('id', -1)
45 | company = Company.objects.get(pk=pk)
46 | except Company.DoesNotExist:
47 | return APIResponse(code=1, msg='对象不存在')
48 |
49 | serializer = CompanySerializer(company, data=request.data)
50 | if serializer.is_valid():
51 | serializer.save()
52 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
53 | else:
54 | print(serializer.errors)
55 | utils.log_error(request, '参数错误')
56 |
57 | return APIResponse(code=1, msg='更新失败')
58 |
59 |
60 | @api_view(['POST'])
61 | def delete(request):
62 |
63 | try:
64 | ids = request.GET.get('ids')
65 | ids_arr = ids.split(',')
66 | Company.objects.filter(id__in=ids_arr).delete()
67 | except Company.DoesNotExist:
68 | return APIResponse(code=1, msg='对象不存在')
69 | return APIResponse(code=0, msg='删除成功')
70 |
--------------------------------------------------------------------------------
/server/myapp/views/index/notice.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from rest_framework.decorators import api_view
3 |
4 | from myapp.handler import APIResponse
5 | from myapp.models import Notice
6 | from myapp.serializers import NoticeSerializer
7 |
8 |
9 | @api_view(['GET'])
10 | def list_api(request):
11 | if request.method == 'GET':
12 | notices = Notice.objects.all().order_by('-create_time')
13 | serializer = NoticeSerializer(notices, many=True)
14 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
15 |
16 |
--------------------------------------------------------------------------------
/server/myapp/views/index/order.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | import datetime
3 |
4 | from rest_framework.decorators import api_view, authentication_classes
5 |
6 | from myapp import utils
7 | from myapp.auth.authentication import TokenAuthtication
8 | from myapp.handler import APIResponse
9 | from myapp.models import Order, Thing
10 | from myapp.serializers import OrderSerializer
11 |
12 |
13 | @api_view(['GET'])
14 | def list_api(request):
15 | if request.method == 'GET':
16 | userId = request.GET.get('userId', -1)
17 | orderStatus = request.GET.get('orderStatus', '')
18 |
19 | orders = Order.objects.all().filter(user=userId).filter(status__contains=orderStatus).order_by('-order_time')
20 | serializer = OrderSerializer(orders, many=True)
21 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
22 |
23 |
24 | @api_view(['POST'])
25 | @authentication_classes([TokenAuthtication])
26 | def create(request):
27 |
28 | data = request.data.copy()
29 | if data['user'] is None or data['thing'] is None or data['count'] is None:
30 | return APIResponse(code=1, msg='参数错误')
31 |
32 | thing = Thing.objects.get(pk=data['thing'])
33 | count = data['count']
34 | if thing.repertory < int(count):
35 | return APIResponse(code=1, msg='库存不足')
36 |
37 | create_time = datetime.datetime.now()
38 | data['create_time'] = create_time
39 | data['order_number'] = str(utils.get_timestamp())
40 | data['status'] = '1'
41 | serializer = OrderSerializer(data=data)
42 | if serializer.is_valid():
43 | serializer.save()
44 | # 减库存(支付后)
45 | # thing.repertory = thing.repertory - int(count)
46 | # thing.save()
47 |
48 | return APIResponse(code=0, msg='创建成功', data=serializer.data)
49 | else:
50 | print(serializer.errors)
51 | return APIResponse(code=1, msg='创建失败')
52 |
53 |
54 | @api_view(['POST'])
55 | @authentication_classes([TokenAuthtication])
56 | def cancel_order(request):
57 | """
58 | cancal
59 | """
60 | try:
61 | pk = request.GET.get('id', -1)
62 | order = Order.objects.get(pk=pk)
63 | except Order.DoesNotExist:
64 | return APIResponse(code=1, msg='对象不存在')
65 |
66 | data = {
67 | 'status': 7
68 | }
69 | serializer = OrderSerializer(order, data=data)
70 | if serializer.is_valid():
71 | serializer.save()
72 | # 加库存
73 | # thingId = request.data['thing']
74 | # thing = Thing.objects.get(pk=thingId)
75 | # thing.repertory = thing.repertory + 1
76 | # thing.save()
77 |
78 | # 加积分
79 | # order.user.score = order.user.score + 1
80 | # order.user.save()
81 |
82 | return APIResponse(code=0, msg='取消成功', data=serializer.data)
83 | else:
84 | print(serializer.errors)
85 | return APIResponse(code=1, msg='更新失败')
86 |
--------------------------------------------------------------------------------
/server/myapp/views/index/post.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from rest_framework.decorators import api_view, authentication_classes
3 |
4 | from myapp import utils
5 | from myapp.auth.authentication import AdminTokenAuthtication
6 | from myapp.handler import APIResponse
7 | from myapp.models import Post
8 | from myapp.permission.permission import isDemoAdminUser
9 | from myapp.serializers import PostSerializer
10 |
11 |
12 | @api_view(['GET'])
13 | def list_user_post_api(request):
14 | if request.method == 'GET':
15 | userId = request.GET.get("userId", None)
16 | if userId is None:
17 | return APIResponse(code=1, msg='userId不能为空')
18 |
19 | posts = Post.objects.filter(user=userId).order_by('-create_time')
20 | serializer = PostSerializer(posts, many=True)
21 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
22 |
23 |
24 | @api_view(['GET'])
25 | def list_company_post_api(request):
26 | if request.method == 'GET':
27 | companyId = request.GET.get("companyId", None)
28 | if companyId is None:
29 | return APIResponse(code=1, msg='companyId不能为空')
30 |
31 | posts = Post.objects.filter(company=companyId).order_by('-create_time')
32 | serializer = PostSerializer(posts, many=True)
33 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
34 |
35 | @api_view(['POST'])
36 | def create(request):
37 |
38 | serializer = PostSerializer(data=request.data)
39 | if serializer.is_valid():
40 | serializer.save()
41 | return APIResponse(code=0, msg='创建成功', data=serializer.data)
42 | else:
43 | print(serializer.errors)
44 | utils.log_error(request, '参数错误')
45 |
46 | return APIResponse(code=1, msg='创建失败')
47 |
--------------------------------------------------------------------------------
/server/myapp/views/index/resume.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from rest_framework.decorators import api_view, authentication_classes
3 |
4 | from myapp import utils
5 | from myapp.auth.authentication import AdminTokenAuthtication
6 | from myapp.handler import APIResponse
7 | from myapp.models import Resume
8 | from myapp.permission.permission import isDemoAdminUser
9 | from myapp.serializers import ResumeSerializer
10 |
11 |
12 |
13 | @api_view(['GET'])
14 | def detail(request):
15 |
16 | try:
17 | user = request.GET.get('user', -1)
18 | resumes = Resume.objects.filter(user=user)
19 | print(resumes)
20 | except Resume.DoesNotExist:
21 | utils.log_error(request, '对象不存在')
22 | return APIResponse(code=1, msg='对象不存在')
23 |
24 | if request.method == 'GET':
25 | if resumes and len(resumes) > 0:
26 | serializer = ResumeSerializer(resumes[0])
27 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
28 | else:
29 | return APIResponse(code=1, msg='不存在')
30 |
31 |
32 |
33 | @api_view(['POST'])
34 | def create(request):
35 |
36 | resumes = Resume.objects.filter(user=request.data['user'])
37 | if resumes and len(resumes) > 0:
38 | return APIResponse(code=1, msg='已创建过了')
39 |
40 | serializer = ResumeSerializer(data=request.data)
41 | if serializer.is_valid():
42 | serializer.save()
43 | return APIResponse(code=0, msg='创建成功', data=serializer.data)
44 | else:
45 | print(serializer.errors)
46 | utils.log_error(request, '参数错误')
47 |
48 | return APIResponse(code=1, msg='创建失败')
49 |
50 |
51 | @api_view(['POST'])
52 | def update(request):
53 |
54 |
55 | try:
56 | pk = request.GET.get('id', -1)
57 | resume = Resume.objects.get(pk=pk)
58 | except Resume.DoesNotExist:
59 | return APIResponse(code=1, msg='对象不存在')
60 |
61 | serializer = ResumeSerializer(resume, data=request.data)
62 | if serializer.is_valid():
63 | serializer.save()
64 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
65 | else:
66 | print(serializer.errors)
67 | utils.log_error(request, '参数错误')
68 |
69 | return APIResponse(code=1, msg='更新失败')
70 |
71 |
72 |
--------------------------------------------------------------------------------
/server/myapp/views/index/tag.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | from rest_framework.decorators import api_view
3 |
4 | from myapp.handler import APIResponse
5 | from myapp.models import Tag
6 | from myapp.serializers import TagSerializer
7 |
8 |
9 | @api_view(['GET'])
10 | def list_api(request):
11 | if request.method == 'GET':
12 | tags = Tag.objects.all().order_by('-create_time')
13 | serializer = TagSerializer(tags, many=True)
14 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
15 |
16 |
--------------------------------------------------------------------------------
/server/myapp/views/index/user.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 | import datetime
3 |
4 | from rest_framework.decorators import api_view, authentication_classes
5 |
6 | from myapp import utils
7 | from myapp.auth.authentication import TokenAuthtication
8 | from myapp.handler import APIResponse
9 | from myapp.models import User
10 | from myapp.serializers import UserSerializer, LoginLogSerializer
11 | from myapp.utils import md5value
12 |
13 |
14 | def make_login_log(request):
15 | try:
16 | username = request.data['username']
17 | data = {
18 | "username": username,
19 | "ip": utils.get_ip(request),
20 | "ua": utils.get_ua(request)
21 | }
22 | serializer = LoginLogSerializer(data=data)
23 | if serializer.is_valid():
24 | serializer.save()
25 | else:
26 | print(serializer.errors)
27 | except Exception as e:
28 | print(e)
29 |
30 |
31 | @api_view(['POST'])
32 | def login(request):
33 | username = request.data['username']
34 | password = utils.md5value(request.data['password'])
35 |
36 | users = User.objects.filter(username=username, password=password)
37 | if len(users) > 0:
38 | user = users[0]
39 |
40 | if user.role in ['1', '3']:
41 | return APIResponse(code=1, msg='该帐号为后台管理员帐号')
42 |
43 | data = {
44 | 'username': username,
45 | 'password': password,
46 | 'token': md5value(username) # 生成令牌
47 | }
48 | serializer = UserSerializer(user, data=data)
49 | if serializer.is_valid():
50 | serializer.save()
51 | make_login_log(request)
52 | return APIResponse(code=0, msg='登录成功', data=serializer.data)
53 | else:
54 | print(serializer.errors)
55 |
56 | return APIResponse(code=1, msg='用户名或密码错误')
57 |
58 |
59 | @api_view(['POST'])
60 | def register(request):
61 | print(request.data)
62 | username = request.data.get('username', None)
63 | password = request.data.get('password', None)
64 | repassword = request.data.get('repassword', None)
65 | if not username or not password or not repassword:
66 | return APIResponse(code=1, msg='用户名或密码不能为空')
67 | if password != repassword:
68 | return APIResponse(code=1, msg='密码不一致')
69 | users = User.objects.filter(username=username)
70 | if len(users) > 0:
71 | return APIResponse(code=1, msg='该用户名已存在')
72 |
73 | data = {
74 | 'username': username,
75 | 'password': password,
76 | 'role': 2, # 角色2
77 | 'status': 0,
78 | }
79 | data.update({'password': utils.md5value(request.data['password'])})
80 | serializer = UserSerializer(data=data)
81 | if serializer.is_valid():
82 | serializer.save()
83 | return APIResponse(code=0, msg='创建成功', data=serializer.data)
84 | else:
85 | print(serializer.errors)
86 |
87 | return APIResponse(code=1, msg='创建失败')
88 |
89 |
90 | @api_view(['GET'])
91 | def info(request):
92 | if request.method == 'GET':
93 | pk = request.GET.get('id', -1)
94 | user = User.objects.get(pk=pk)
95 | serializer = UserSerializer(user)
96 | return APIResponse(code=0, msg='查询成功', data=serializer.data)
97 |
98 |
99 | @api_view(['POST'])
100 | @authentication_classes([TokenAuthtication])
101 | def update(request):
102 | try:
103 | pk = request.GET.get('id', -1)
104 | user = User.objects.get(pk=pk)
105 | except User.DoesNotExist:
106 | return APIResponse(code=1, msg='对象不存在')
107 |
108 | data = request.data.copy()
109 | if 'username' in data.keys():
110 | del data['username']
111 | if 'password' in data.keys():
112 | del data['password']
113 | if 'role' in data.keys():
114 | del data['role']
115 | serializer = UserSerializer(user, data=data)
116 | print(serializer.is_valid())
117 | if serializer.is_valid():
118 | serializer.save()
119 | return APIResponse(code=0, msg='更新成功', data=serializer.data)
120 | else:
121 | print(serializer.errors)
122 |
123 | return APIResponse(code=1, msg='更新失败')
124 |
125 |
126 | @api_view(['POST'])
127 | @authentication_classes([TokenAuthtication])
128 | def updatePwd(request):
129 |
130 | try:
131 | pk = request.GET.get('id', -1)
132 | user = User.objects.get(pk=pk)
133 | except User.DoesNotExist:
134 | return APIResponse(code=1, msg='对象不存在')
135 |
136 | print(user.role)
137 | if user.role != '2':
138 | return APIResponse(code=1, msg='参数非法')
139 |
140 | password = request.data.get('password', None)
141 | newPassword1 = request.data.get('newPassword1', None)
142 | newPassword2 = request.data.get('newPassword2', None)
143 |
144 | if not password or not newPassword1 or not newPassword2:
145 | return APIResponse(code=1, msg='不能为空')
146 |
147 | if user.password != utils.md5value(password):
148 | return APIResponse(code=1, msg='原密码不正确')
149 |
150 | if newPassword1 != newPassword2:
151 | return APIResponse(code=1, msg='两次密码不一致')
152 |
153 | data = request.data.copy()
154 | data.update({'password': utils.md5value(newPassword1)})
155 | serializer = UserSerializer(user, data=data)
156 | if serializer.is_valid():
157 | serializer.save()
158 | return APIResponse(code=0, msg='更新成功', data=serializer.data)
159 | else:
160 | print(serializer.errors)
161 |
162 | return APIResponse(code=1, msg='更新失败')
--------------------------------------------------------------------------------
/server/readme.md:
--------------------------------------------------------------------------------
1 | ### 后端部署步骤
2 |
3 | > 部署过程中,如遇问题可咨询作者:lengqin1024(微信)
4 |
5 | 1. 安装mysql数据库,启动服务
6 | 2. 打开cmd命令行,进入mysql,并新建数据库
7 | ```
8 | mysql -u root -p
9 | CREATE DATABASE IF NOT EXISTS python_job DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
10 | ```
11 | 3. 恢复sql数据
12 | ```
13 | use xxx
14 | source xxxx.sql
15 | ```
16 | 4. 修改settings.py中的配置信息
17 | 5. 复制资源,将upload文件夹复制到server目录下
18 | 6. 安装python 3.8
19 | 7. 安装依赖包
20 | ```
21 | pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
22 | ```
23 | 运行项目
24 | ```
25 | python manage.py runserver 0.0.0.0:9003
26 | ```
27 | 7. 后期维护改动
28 |
29 | 将修改的py文件覆盖服务器的py文件即可,重启django
30 |
31 | ### 删除数据库
32 |
33 | drop database if exists shop;
34 |
35 | ### 创建数据库
36 |
37 | CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
38 |
39 |
40 | ### 迁移数据库表
41 |
42 | ```
43 | python manage.py makemigrations;
44 |
45 | python manage.py migrate;
46 |
47 | python manage.py makemigrations myapp;
48 |
49 | python manage.py migrate myapp;
50 | ```
51 |
52 | ### 跨域配置
53 |
54 | django-cors-headers
55 |
56 | ### 多对多技术参考
57 |
58 | https://www.cnblogs.com/SunshineKimi/p/14140900.html
59 |
60 | ### 二级分类设计
61 | https://blog.csdn.net/weixin_47971206/article/details/124199978
62 |
63 | ### 常见问题
64 |
65 | 多对多的查询可通过related_name别名查询
66 | join查询
67 | ForeignKey的时候字段会自动加_id后缀
68 | 学习SerializerMethodField
69 | 跨域配置 django-cors-headers
70 | 数据库备份命令:
71 | mysqldump -u root -p --databases 数据库名称 > xxx.sql
72 | 数据库还原命令:
73 | source D:/xxx/xxx/shop.sql;
74 | 创建管理员命令:
75 | insert into b_user(username,password,role,status) values('admin111',md5('admin111'),1,'0');
76 |
77 | 接口请求频次限制
78 |
79 |
80 | ### 登录接口
81 |
82 | 调login -> 生成token
83 |
84 | ### 注意
85 |
86 | update接口的时候,如果model里面存在多对多字段,则需要设置explode
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/server/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==3.2.11
2 | PyMySQL==1.0.2
3 | djangorestframework==3.13.0
4 | django-cors-headers==3.13.0
5 | Pillow==9.1.1
6 | psutil==5.9.4
--------------------------------------------------------------------------------
/server/server/__init__.py:
--------------------------------------------------------------------------------
1 | import pymysql
2 | pymysql.install_as_MySQLdb()
3 |
4 | print("===============install pymysql==============")
--------------------------------------------------------------------------------
/server/server/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for server project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/server/server/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for server project.
3 |
4 | Generated by 'django-admin startproject' using Django 4.1.4.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/4.1/ref/settings/
11 | """
12 | import os
13 | from pathlib import Path
14 |
15 | # Build paths inside the project like this: BASE_DIR / 'subdir'.
16 | # BASE_DIR = Path(__file__).resolve().parent.parent
17 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = 'django-insecure-sz@madp0ifx!b)^lg_g!f+5s*w7w_=sjgq-k+erzb%x42$^r!d'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = ['*']
29 |
30 | # Application definition
31 |
32 | INSTALLED_APPS = [
33 | 'django.contrib.admin',
34 | 'django.contrib.auth',
35 | 'django.contrib.contenttypes',
36 | 'django.contrib.sessions',
37 | 'django.contrib.messages',
38 | 'django.contrib.staticfiles',
39 | 'rest_framework',
40 | 'corsheaders', # 跨域
41 | 'myapp'
42 | ]
43 |
44 | MIDDLEWARE = [
45 | 'django.middleware.security.SecurityMiddleware',
46 | 'django.contrib.sessions.middleware.SessionMiddleware',
47 | 'corsheaders.middleware.CorsMiddleware', # 跨域配置
48 | 'django.middleware.common.CommonMiddleware',
49 | 'django.middleware.csrf.CsrfViewMiddleware',
50 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
51 | 'django.contrib.messages.middleware.MessageMiddleware',
52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
53 | 'myapp.middlewares.LogMiddleware.OpLogs'
54 | ]
55 |
56 | CORS_ORIGIN_ALLOW_ALL = True # 允许跨域
57 |
58 | ROOT_URLCONF = 'server.urls'
59 |
60 | TEMPLATES = [
61 | {
62 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
63 | 'DIRS': [],
64 | 'APP_DIRS': True,
65 | 'OPTIONS': {
66 | 'context_processors': [
67 | 'django.template.context_processors.debug',
68 | 'django.template.context_processors.request',
69 | 'django.contrib.auth.context_processors.auth',
70 | 'django.contrib.messages.context_processors.messages',
71 | ],
72 | },
73 | },
74 | ]
75 |
76 | WSGI_APPLICATION = 'server.wsgi.application'
77 |
78 | # Database
79 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases
80 |
81 | DATABASES = {
82 | 'default': {
83 | 'ENGINE': 'django.db.backends.mysql',
84 | 'NAME': 'python_job',
85 | 'USER': 'root',
86 | 'PASSWORD': '4643830',
87 | 'HOST': '127.0.0.1',
88 | 'PORT': '3306',
89 | 'OPTIONS': {
90 | "init_command": "SET foreign_key_checks = 0;",
91 | }
92 | }
93 | }
94 |
95 | # Password validation
96 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
97 |
98 | AUTH_PASSWORD_VALIDATORS = [
99 | {
100 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
101 | },
102 | {
103 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
104 | },
105 | {
106 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
107 | },
108 | {
109 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
110 | },
111 | ]
112 |
113 | # Internationalization
114 | # https://docs.djangoproject.com/en/4.1/topics/i18n/
115 |
116 |
117 | LANGUAGE_CODE = 'zh-hans'
118 |
119 | # 时区
120 | TIME_ZONE = 'Asia/Shanghai'
121 |
122 | USE_I18N = True
123 |
124 | USE_L10N = True
125 |
126 | USE_TZ = False
127 |
128 | # 日期时间格式
129 | DATE_FORMAT = 'Y-m-d'
130 | DATETIME_FORMAT = 'Y-m-d H:i:s'
131 |
132 | # 上传文件路径
133 | # 并在urls.py配置+static
134 | MEDIA_ROOT = os.path.join(BASE_DIR, 'upload/')
135 | MEDIA_URL = '/upload/'
136 |
137 | # Static files (CSS, JavaScript, Images)
138 | # https://docs.djangoproject.com/en/4.1/howto/static-files/
139 |
140 | STATIC_URL = 'static/'
141 |
142 | # Default primary key field type
143 | # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
144 |
145 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
146 |
147 | # 跨域配置
148 | CORS_ALLOW_CREDENTIALS = True
149 | CORS_ALLOW_ALL_ORIGINS = True
150 | CORS_ALLOW_HEADERS = '*'
151 |
--------------------------------------------------------------------------------
/server/server/urls.py:
--------------------------------------------------------------------------------
1 | """server URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/4.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.conf.urls.static import static
17 | from django.contrib import admin
18 | from django.urls import path, include
19 |
20 | from server import settings
21 |
22 | urlpatterns = [
23 | path('admin/', admin.site.urls),
24 | path('myapp/', include('myapp.urls')),
25 | ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
26 |
--------------------------------------------------------------------------------
/server/server/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for server project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/server/upload/company/1685770491227.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/company/1685770491227.png
--------------------------------------------------------------------------------
/server/upload/company/1685770768426.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/company/1685770768426.jpeg
--------------------------------------------------------------------------------
/server/upload/company/1685771081809.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/company/1685771081809.png
--------------------------------------------------------------------------------
/server/upload/company/1685848419951.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/company/1685848419951.png
--------------------------------------------------------------------------------
/server/upload/cover/1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/cover/1.jpeg
--------------------------------------------------------------------------------
/server/upload/img/Wechat.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/img/Wechat.jpeg
--------------------------------------------------------------------------------
/server/upload/img/a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/img/a.png
--------------------------------------------------------------------------------
/server/upload/img/b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/img/b.png
--------------------------------------------------------------------------------
/server/upload/img/weixin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/img/weixin.png
--------------------------------------------------------------------------------
/server/upload/raw/1685780971830.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/raw/1685780971830.jpeg
--------------------------------------------------------------------------------
/server/upload/resume/1685772029168.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/resume/1685772029168.png
--------------------------------------------------------------------------------
/server/upload/resume/1685772036385.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/resume/1685772036385.jpeg
--------------------------------------------------------------------------------
/server/upload/resume/1685772067199.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/resume/1685772067199.jpeg
--------------------------------------------------------------------------------
/server/upload/resume/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/resume/logo.png
--------------------------------------------------------------------------------
/server/upload/resume/logo_Yvy8kmb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/server/upload/resume/logo_Yvy8kmb.png
--------------------------------------------------------------------------------
/web/.eslintignore:
--------------------------------------------------------------------------------
1 |
2 | *.sh
3 | node_modules
4 | *.md
5 | *.woff
6 | *.ttf
7 | .vscode
8 | .idea
9 | dist
10 | /public
11 | /docs
12 | .husky
13 | .local
14 | /bin
15 | Dockerfile
16 |
--------------------------------------------------------------------------------
/web/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | es6: true,
7 | },
8 | parser: 'vue-eslint-parser',
9 | parserOptions: {
10 | parser: '@typescript-eslint/parser',
11 | ecmaVersion: 2020,
12 | sourceType: 'module',
13 | jsxPragma: 'React',
14 | ecmaFeatures: {
15 | jsx: true,
16 | },
17 | },
18 | extends: ['plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
19 | rules: {
20 | 'vue/script-setup-uses-vars': 'error',
21 | '@typescript-eslint/ban-ts-ignore': 'off',
22 | '@typescript-eslint/explicit-function-return-type': 'off',
23 | '@typescript-eslint/no-explicit-any': 'off',
24 | '@typescript-eslint/no-var-requires': 'off',
25 | '@typescript-eslint/no-empty-function': 'off',
26 | 'vue/custom-event-name-casing': 'off',
27 | 'no-use-before-define': 'off',
28 | '@typescript-eslint/no-use-before-define': 'off',
29 | '@typescript-eslint/ban-ts-comment': 'off',
30 | '@typescript-eslint/ban-types': 'off',
31 | '@typescript-eslint/no-non-null-assertion': 'off',
32 | '@typescript-eslint/explicit-module-boundary-types': 'off',
33 | '@typescript-eslint/no-unused-vars': 'off',
34 | 'no-unused-vars': 'off',
35 | 'space-before-function-paren': 'off',
36 |
37 | 'vue/attributes-order': 'off',
38 | 'vue/one-component-per-file': 'off',
39 | 'vue/html-closing-bracket-newline': 'off',
40 | 'vue/max-attributes-per-line': 'off',
41 | 'vue/multiline-html-element-content-newline': 'off',
42 | 'vue/singleline-html-element-content-newline': 'off',
43 | 'vue/attribute-hyphenation': 'off',
44 | 'vue/require-default-prop': 'off',
45 | 'vue/require-explicit-emits': 'off',
46 | 'vue/html-self-closing': [
47 | 'error',
48 | {
49 | html: {
50 | void: 'always',
51 | normal: 'never',
52 | component: 'always',
53 | },
54 | svg: 'always',
55 | math: 'always',
56 | },
57 | ],
58 | 'vue/multi-word-component-names': 'off',
59 | },
60 | };
61 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | dist-ssr
5 | .local
6 | .history
7 | # local env files
8 | .env.local
9 | .env.*.local
10 | .eslintcache
11 | .github
12 | .husky
13 | .vscode
14 |
15 | # Log files
16 | npm-debug.log*
17 | yarn-debug.log*
18 | yarn-error.log*
19 | pnpm-debug.log*
20 | pnpm-lock.yaml*
21 |
22 | # Editor directories and files
23 | .idea
24 | # .vscode
25 | *.suo
26 | *.ntvs*
27 | *.njsproj
28 | *.sln
29 | *.sw?
30 | ./packages
31 | ./history
32 |
--------------------------------------------------------------------------------
/web/.stylelintignore:
--------------------------------------------------------------------------------
1 | /dist/*
2 | /public/*
3 | public/*
4 |
--------------------------------------------------------------------------------
/web/README.md:
--------------------------------------------------------------------------------
1 | ### 学习文档
2 |
3 | > 部署过程中,如遇问题可咨询作者:lengqin1024(微信)
4 |
5 | #### 部署步骤
6 |
7 | 1. 修改constants.ts中的BASE_URL
8 | 2. vite build
9 | 3. 将dist部署到nginx
10 |
11 |
12 | #### 配置解释
13 |
14 | 1. env.development 开发环境配置
15 | 2. eslintrc.js 代码规范化提示
16 | 3. vite.config.js vite 开发服务器配置
17 |
18 | #### 常见问题
19 |
20 | ##### 变量
21 | https://blog.csdn.net/qq_41636947/article/details/117907448
22 |
23 | ##### antd的css引入方式
24 | 在index.html里面引入的cdn
25 |
26 | ##### cdn
27 | https://cdn.jsdelivr.net/npm/ant-design-vue@3.2.20/dist/
28 | https://cdn.staticfile.org/ant-design-vue/3.2.20/antd.min.css
29 |
30 | #### public文件夹内容在build后会自动打到dist中
31 |
--------------------------------------------------------------------------------
/web/build/constant.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @name Config
3 | * @description 项目配置
4 | */
5 |
6 |
7 | // 本地服务端口
8 | export const VITE_PORT = 3000;
9 |
10 | // 包依赖分析
11 | export const ANALYSIS = true;
12 |
13 | // 代码压缩
14 | export const COMPRESSION = true;
15 |
16 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/autoImport.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @name AutoImportDeps
3 | * @description 按需加载,自动引入
4 | */
5 | import AutoImport from 'unplugin-auto-import/vite';
6 | // import { AntDesignVueResolver} from 'unplugin-vue-components/resolvers';
7 |
8 | export const AutoImportDeps = () => {
9 | return AutoImport({
10 | dts: 'types/auto-imports.d.ts',
11 | imports: [
12 | 'vue',
13 | 'pinia',
14 | 'vue-router',
15 | {
16 | '@vueuse/core': [],
17 | },
18 | {
19 | 'naive-ui': ['useDialog', 'useMessage', 'useNotification', 'useLoadingBar'],
20 | },
21 | ],
22 | resolvers: [
23 | // AntDesignVueResolver(),
24 | ],
25 | });
26 | };
27 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/component.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @name AutoRegistryComponents
3 | * @description 按需加载,自动引入组件
4 | */
5 | import Components from 'unplugin-vue-components/vite';
6 | import {
7 | ElementPlusResolver,
8 | VueUseComponentsResolver,
9 | AntDesignVueResolver,
10 | TDesignResolver,
11 | NaiveUiResolver,
12 | } from 'unplugin-vue-components/resolvers';
13 | export const AutoRegistryComponents = () => {
14 | return Components({
15 | dirs: ['src/components'],
16 | extensions: ['vue'],
17 | deep: true,
18 | dts: 'types/components.d.ts',
19 | directoryAsNamespace: false,
20 | globalNamespaces: [],
21 | directives: true,
22 | importPathTransform: (v) => v,
23 | allowOverrides: false,
24 | include: [/\.vue$/, /\.vue\?vue/],
25 | exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/],
26 | resolvers: [
27 | ElementPlusResolver(),
28 | VueUseComponentsResolver(),
29 | AntDesignVueResolver(),
30 | TDesignResolver({
31 | library: 'vue-next',
32 | }),
33 | NaiveUiResolver(),
34 | ],
35 | });
36 | };
37 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/compress.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @name ConfigCompressPlugin
3 | * @description 开启.gz压缩
4 | */
5 | import viteCompression from 'vite-plugin-compression';
6 | import { COMPRESSION } from '../../constant';
7 |
8 | export const ConfigCompressPlugin = () => {
9 | if (COMPRESSION) {
10 | return viteCompression({
11 | verbose: true, // 默认即可
12 | disable: false, //开启压缩(不禁用),默认即可
13 | deleteOriginFile: false, //删除源文件
14 | threshold: 10240, //压缩前最小文件大小
15 | algorithm: 'gzip', //压缩算法
16 | ext: '.gz', //文件类型
17 | });
18 | }
19 | return [];
20 | };
21 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/imagemin.ts:
--------------------------------------------------------------------------------
1 | import viteImagemin from 'vite-plugin-imagemin';
2 |
3 | export function ConfigImageminPlugin() {
4 | const plugin = viteImagemin({
5 | gifsicle: {
6 | optimizationLevel: 7,
7 | interlaced: false,
8 | },
9 | mozjpeg: {
10 | quality: 20,
11 | },
12 | optipng: {
13 | optimizationLevel: 7,
14 | },
15 | pngquant: {
16 | quality: [0.8, 0.9],
17 | speed: 4,
18 | },
19 | svgo: {
20 | plugins: [
21 | {
22 | name: 'removeViewBox',
23 | },
24 | {
25 | name: 'removeEmptyAttrs',
26 | active: false,
27 | },
28 | ],
29 | },
30 | });
31 | return plugin;
32 | }
33 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @name createVitePlugins
3 | * @description 封装plugins数组统一调用
4 | */
5 | import {PluginOption} from 'vite';
6 | import vue from '@vitejs/plugin-vue';
7 | import vueJsx from '@vitejs/plugin-vue-jsx';
8 | import {AutoImportDeps} from './autoImport';
9 | import {ConfigCompressPlugin} from './compress';
10 | import {ConfigRestartPlugin} from './restart';
11 | import {ConfigProgressPlugin} from './progress';
12 | import {ConfigVisualizerConfig} from "./visualizer";
13 |
14 | export function createVitePlugins(isBuild: boolean) {
15 | const vitePlugins = [
16 | // vue支持
17 | vue(),
18 | // JSX支持
19 | vueJsx(),
20 | // setup语法糖组件名支持
21 | // vueSetupExtend(),
22 | // 提供https证书
23 | // VitePluginCertificate({
24 | // source: 'coding',
25 | // }) as PluginOption,
26 | ];
27 |
28 | // 自动按需引入组件
29 | // vitePlugins.push(AutoRegistryComponents());
30 |
31 | // 自动按需引入依赖
32 | vitePlugins.push(AutoImportDeps());
33 |
34 | // 自动生成路由
35 | // vitePlugins.push(ConfigPagesPlugin());
36 |
37 | // 开启.gz压缩 rollup-plugin-gzip
38 | vitePlugins.push(ConfigCompressPlugin());
39 |
40 | // 监听配置文件改动重启
41 | vitePlugins.push(ConfigRestartPlugin());
42 |
43 | // 构建时显示进度条
44 | vitePlugins.push(ConfigProgressPlugin());
45 |
46 | // 构建时显示进度条
47 | vitePlugins.push(ConfigVisualizerConfig());
48 |
49 |
50 | return vitePlugins;
51 | }
52 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/progress.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @name ConfigProgressPlugin
3 | * @description 构建显示进度条
4 | */
5 |
6 | import progress from 'vite-plugin-progress';
7 | export const ConfigProgressPlugin = () => {
8 | return progress();
9 | };
10 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/restart.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @name ConfigRestartPlugin
3 | * @description 监听配置文件修改自动重启Vite
4 | */
5 | import ViteRestart from 'vite-plugin-restart';
6 | export const ConfigRestartPlugin = () => {
7 | return ViteRestart({
8 | restart: ['*.config.[jt]s', '**/config/*.[jt]s'],
9 | });
10 | };
11 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/unocss.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @name ConfigUnocssPlugin
3 | * @description 监听配置文件修改自动重启Vite
4 | */
5 |
6 | // Unocss
7 | import Unocss from 'unocss/vite';
8 |
9 | export const ConfigUnocssPlugin = () => {
10 | return Unocss();
11 | };
12 |
--------------------------------------------------------------------------------
/web/build/vite/plugins/visualizer.ts:
--------------------------------------------------------------------------------
1 | import visualizer from 'rollup-plugin-visualizer';
2 | import { ANALYSIS } from '../../constant';
3 |
4 | export function ConfigVisualizerConfig() {
5 | if (ANALYSIS) {
6 | return visualizer({
7 | filename: 'dist/report.html',
8 | open: true,
9 | gzipSize: true,
10 | emitFile: false
11 | });
12 | }
13 | return [];
14 | }
15 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 求职招聘网站
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "my-web-app",
3 | "version": "0.1.2",
4 | "author": "lengqin1024",
5 | "scripts": {
6 | "dev": "vite --mode development",
7 | "build": "vite build",
8 | "preview": "vite preview"
9 | },
10 | "dependencies": {
11 | "@ant-design/icons-vue": "^6.1.0",
12 | "@vueuse/components": "^9.10.0",
13 | "@vueuse/core": "^9.10.0",
14 | "ant-design-vue": "^3.2.20",
15 | "axios": "^1.2.2",
16 | "pinia": "^2.0.28",
17 | "pinia-plugin-persistedstate": "^3.0.2",
18 | "qs": "^6.11.0",
19 | "vue": "^3.2.45",
20 | "vue-router": "^4.1.6"
21 | },
22 | "devDependencies": {
23 | "@types/qs": "^6.9.7",
24 | "@typescript-eslint/eslint-plugin": "^5.48.0",
25 | "@typescript-eslint/parser": "^5.48.0",
26 | "@vitejs/plugin-vue": "^4.0.0",
27 | "@vitejs/plugin-vue-jsx": "^3.0.0",
28 | "autoprefixer": "^10.4.13",
29 | "eslint": "8.22.0",
30 | "eslint-config-prettier": "^8.6.0",
31 | "eslint-define-config": "^1.13.0",
32 | "eslint-plugin-prettier": "^4.2.1",
33 | "eslint-plugin-vue": "^9.8.0",
34 | "less": "^4.1.3",
35 | "less-loader": "^11.1.0",
36 | "postcss": "^8.4.21",
37 | "postcss-html": "^1.5.0",
38 | "postcss-less": "^6.0.0",
39 | "prettier": "^2.8.3",
40 | "rollup-plugin-visualizer": "^5.9.0",
41 | "stylelint": "^14.16.1",
42 | "stylelint-config-standard": "^29.0.0",
43 | "stylelint-order": "^6.0.1",
44 | "typescript": "4.9.4",
45 | "unplugin-auto-import": "^0.12.2",
46 | "vite": "^4.0.3",
47 | "vite-plugin-compression": "^0.5.1",
48 | "vite-plugin-progress": "^0.0.6",
49 | "vite-plugin-restart": "^0.3.1"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/web/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/web/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 140,
3 | semi: true,
4 | vueIndentScriptAndStyle: true,
5 | singleQuote: true,
6 | trailingComma: 'all',
7 | proseWrap: 'never',
8 | htmlWhitespaceSensitivity: 'strict',
9 | endOfLine: 'auto',
10 | };
11 |
--------------------------------------------------------------------------------
/web/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/public/favicon.ico
--------------------------------------------------------------------------------
/web/public/images/admin-login-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/public/images/admin-login-bg.jpg
--------------------------------------------------------------------------------
/web/public/images/bg2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/public/images/bg2.jpg
--------------------------------------------------------------------------------
/web/public/images/demo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/public/images/demo.jpg
--------------------------------------------------------------------------------
/web/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
19 |
--------------------------------------------------------------------------------
/web/src/api/admin/ad.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/admin/ad/list',
5 | create = '/myapp/admin/ad/create',
6 | update = '/myapp/admin/ad/update',
7 | delete = '/myapp/admin/ad/delete',
8 | }
9 |
10 | const listApi = async (params: any) =>
11 | get({url: URL.list, params: params, data: {}, headers: {}});
12 | const createApi = async (data: any) =>
13 | post({
14 | url: URL.create,
15 | params: {},
16 | data: data,
17 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
18 | });
19 | const updateApi = async (params: any, data: any) =>
20 | post({
21 | url: URL.update,
22 | params: params,
23 | data: data,
24 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
25 | });
26 | const deleteApi = async (params: any) =>
27 | post({url: URL.delete, params: params, headers: {}});
28 |
29 | export {listApi, createApi, updateApi, deleteApi};
30 |
--------------------------------------------------------------------------------
/web/src/api/admin/classification.ts:
--------------------------------------------------------------------------------
1 | import { get, post } from '/@/utils/http/axios';
2 | enum URL {
3 | list = '/myapp/admin/classification/list',
4 | create = '/myapp/admin/classification/create',
5 | update = '/myapp/admin/classification/update',
6 | delete = '/myapp/admin/classification/delete',
7 | }
8 |
9 | const listApi = async (params: any) => get({ url: URL.list, params: params, data: {}, headers: {} });
10 | const createApi = async (data: any) =>
11 | post({ url: URL.create, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
12 | const updateApi = async (params: any, data: any) =>
13 | post({ url: URL.update, params: params, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
14 | const deleteApi = async (params: any) => post({ url: URL.delete, params: params, headers: {} });
15 |
16 | export { listApi, createApi, updateApi, deleteApi };
17 |
--------------------------------------------------------------------------------
/web/src/api/admin/comment.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/admin/comment/list',
5 | create = '/myapp/admin/comment/create',
6 | delete = '/myapp/admin/comment/delete',
7 | listThingComments = '/api/comment/listThingComments',
8 | listUserComments = '/api/comment/listUserComments',
9 | like = '/api/comment/like'
10 | }
11 |
12 | const listApi = async (params: any) => get({url: URL.list, params: params, data: {}, headers: {}});
13 | const createApi = async (data: any) => post({
14 | url: URL.create,
15 | params: {},
16 | data: data,
17 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
18 | });
19 | const deleteApi = async (params: any) => post({url: URL.delete, params: params, headers: {}});
20 | const listThingCommentsApi = async (params: any) => get({url: URL.listThingComments, params: params, data: {}, headers: {}});
21 | const listUserCommentsApi = async (params: any) => get({url: URL.listUserComments, params: params, data: {}, headers: {}});
22 | const likeApi = async (params: any) => post({url: URL.like, params: params, headers: {}});
23 |
24 | export {listApi, createApi, deleteApi, listThingCommentsApi, listUserCommentsApi, likeApi};
25 |
--------------------------------------------------------------------------------
/web/src/api/admin/company.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | list = '/myapp/admin/company/list',
7 | create = '/myapp/admin/company/create',
8 | update = '/myapp/admin/company/update',
9 | delete = '/myapp/admin/company/delete',
10 | }
11 |
12 | const listApi = async (params: any) => get({ url: URL.list, params: params, data: {}, headers: {} });
13 | const createApi = async (data: any) =>
14 | post({ url: URL.create, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
15 | const updateApi = async (params:any, data: any) =>
16 | post({ url: URL.update,params: params, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
17 | const deleteApi = async (params: any) => post({ url: URL.delete, params: params, headers: {} });
18 |
19 | export { listApi, createApi, updateApi, deleteApi };
20 |
--------------------------------------------------------------------------------
/web/src/api/admin/log.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | loginLogList = '/myapp/admin/loginLog/list',
5 | opLogList = '/myapp/admin/opLog/list',
6 | errorLogList = '/myapp/admin/errorLog/list',
7 | }
8 |
9 | const listLoginLogApi = async (params: any) =>
10 | get({url: URL.loginLogList, params: params, data: {}, headers: {}});
11 | const listOpLogListApi = async (params: any) =>
12 | get({url: URL.opLogList, params: params, data: {}, headers: {}});
13 | const listErrorLogListApi = async (params: any) =>
14 | get({url: URL.errorLogList, params: params, data: {}, headers: {}});
15 |
16 | export {listLoginLogApi, listOpLogListApi, listErrorLogListApi};
17 |
--------------------------------------------------------------------------------
/web/src/api/admin/notice.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/admin/notice/list',
5 | create = '/myapp/admin/notice/create',
6 | update = '/myapp/admin/notice/update',
7 | delete = '/myapp/admin/notice/delete',
8 | }
9 |
10 | const listApi = async (params: any) =>
11 | get({url: URL.list, params: params, data: {}, headers: {}});
12 | const createApi = async (data: any) =>
13 | post({
14 | url: URL.create,
15 | params: {},
16 | data: data,
17 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
18 | });
19 | const updateApi = async (params: any, data: any) =>
20 | post({
21 | url: URL.update,
22 | params: params,
23 | data: data,
24 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
25 | });
26 | const deleteApi = async (params: any) =>
27 | post({url: URL.delete, params: params, headers: {}});
28 |
29 | export {listApi, createApi, updateApi, deleteApi};
30 |
--------------------------------------------------------------------------------
/web/src/api/admin/order.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/admin/order/list',
5 | create = '/myapp/admin/order/create',
6 | update = '/myapp/admin/order/update',
7 | delete = '/myapp/admin/order/delete',
8 | cancel = '/myapp/admin/order/cancel_order',
9 | cancelUserOrder = '/api/order/cancelUserOrder',
10 | userOrderList = '/api/order/userOrderList',
11 | }
12 |
13 | const listApi = async (params: any) =>
14 | get({url: URL.list, params: params, data: {}, headers: {}});
15 | const userOrderListApi = async (params: any) =>
16 | get({url: URL.userOrderList, params: params, data: {}, headers: {}});
17 |
18 | const createApi = async (data: any) =>
19 | post({
20 | url: URL.create,
21 | params: {},
22 | data: data,
23 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
24 | });
25 | const updateApi = async (params: any, data: any) =>
26 | post({
27 | url: URL.update,
28 | params: params,
29 | data: data,
30 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
31 | });
32 | const deleteApi = async (params: any) =>
33 | post({url: URL.delete, params: params, headers: {}});
34 |
35 | const cancelApi = async (params: any) =>
36 | post({url: URL.cancel, params: params, headers: {}});
37 |
38 | const cancelUserOrderApi = async (params: any) =>
39 | post({url: URL.cancelUserOrder, params: params, headers: {}});
40 |
41 | export {listApi, userOrderListApi, createApi, updateApi, deleteApi, cancelApi, cancelUserOrderApi};
42 |
--------------------------------------------------------------------------------
/web/src/api/admin/overview.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/admin/overview/count',
5 | sysInfo= '/myapp/admin/overview/sysInfo',
6 | }
7 |
8 | const listApi = async (params: any) =>
9 | get({url: URL.list, params: params, data: {}, headers: {}});
10 |
11 |
12 | const sysInfoApi = async (params: any) =>
13 | get({url: URL.sysInfo, params: params, data: {}, headers: {}});
14 |
15 | export {listApi, sysInfoApi};
16 |
--------------------------------------------------------------------------------
/web/src/api/admin/resume.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | list = '/myapp/admin/resume/list',
7 | create = '/myapp/admin/resume/create',
8 | update = '/myapp/admin/resume/update',
9 | delete = '/myapp/admin/resume/delete',
10 | }
11 |
12 | const listApi = async (params: any) => get({ url: URL.list, params: params, data: {}, headers: {} });
13 | const createApi = async (data: any) =>
14 | post({ url: URL.create, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
15 | const updateApi = async (params:any, data: any) =>
16 | post({ url: URL.update,params: params, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
17 | const deleteApi = async (params: any) => post({ url: URL.delete, params: params, headers: {} });
18 |
19 | export { listApi, createApi, updateApi, deleteApi };
20 |
--------------------------------------------------------------------------------
/web/src/api/admin/tag.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/admin/tag/list',
5 | create = '/myapp/admin/tag/create',
6 | update = '/myapp/admin/tag/update',
7 | delete = '/myapp/admin/tag/delete',
8 | }
9 |
10 | const listApi = async (params: any) =>
11 | get({url: URL.list, params: params, data: {}, headers: {}});
12 | const createApi = async (data: any) =>
13 | post({
14 | url: URL.create,
15 | params: {},
16 | data: data,
17 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
18 | });
19 | const updateApi = async (params: any, data: any) =>
20 | post({
21 | url: URL.update,
22 | params: params,
23 | data: data,
24 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
25 | });
26 | const deleteApi = async (params: any) =>
27 | post({url: URL.delete, params: params, headers: {}});
28 |
29 | export {listApi, createApi, updateApi, deleteApi};
30 |
--------------------------------------------------------------------------------
/web/src/api/admin/thing.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | list = '/myapp/admin/thing/list',
7 | create = '/myapp/admin/thing/create',
8 | update = '/myapp/admin/thing/update',
9 | delete = '/myapp/admin/thing/delete',
10 | detail = '/api/thing/detail',
11 | }
12 |
13 | const listApi = async (params: any) => get({ url: URL.list, params: params, data: {}, headers: {} });
14 | const createApi = async (data: any) =>
15 | post({ url: URL.create, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
16 | const updateApi = async (params:any, data: any) =>
17 | post({ url: URL.update,params: params, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
18 | const deleteApi = async (params: any) => post({ url: URL.delete, params: params, headers: {} });
19 | const detailApi = async (params: any) => get({ url: URL.detail, params: params, headers: {} });
20 |
21 | export { listApi, createApi, updateApi, deleteApi, detailApi };
22 |
--------------------------------------------------------------------------------
/web/src/api/admin/user.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | login = '/myapp/admin/adminLogin',
7 | userList = '/myapp/admin/user/list',
8 | detail = '/api/user/detail',
9 | create = '/myapp/admin/user/create',
10 | update = '/myapp/admin/user/update',
11 | delete = '/myapp/admin/user/delete',
12 | userLogin = '/api/user/userLogin',
13 | userRegister = '/api/user/userRegister',
14 | updateUserPwd = '/api/user/updatePwd',
15 | updateUserInfo = '/api/user/updateUserInfo'
16 | }
17 | interface LoginRes {
18 | token: string;
19 | }
20 |
21 | export interface LoginData {
22 | username: string;
23 | password: string;
24 | }
25 |
26 | const loginApi = async (data: LoginData) => post({ url: URL.login, data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
27 | const listApi = async (params: any) => get({ url: URL.userList, params: params, data: {}, headers: {} });
28 | const detailApi = async (params: any) => get({ url: URL.detail, params: params, data: {}, headers: {} });
29 | const createApi = async (data: any) => post({ url: URL.create, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
30 | const updateApi = async (params: any, data: any) => post({ url: URL.update,params: params, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
31 | const deleteApi = async (params: any) => post({ url: URL.delete, params: params, headers: {} });
32 | const userLoginApi = async (data: LoginData) => post({ url: URL.userLogin, data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
33 | const userRegisterApi = async (data: any) => post({ url: URL.userRegister, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
34 | const updateUserPwdApi = async (params: any) => post({ url: URL.updateUserPwd, params: params });
35 | const updateUserInfoApi = async (data: any) => post({ url: URL.updateUserInfo, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
36 |
37 | export { loginApi, listApi, detailApi, createApi, updateApi, deleteApi, userLoginApi, userRegisterApi, updateUserPwdApi, updateUserInfoApi};
38 |
--------------------------------------------------------------------------------
/web/src/api/index/address.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/index/address/list',
5 | create = '/myapp/index/address/create',
6 | update = '/myapp/index/address/update',
7 | delete = '/myapp/index/address/delete',
8 | }
9 |
10 | const listApi = async (params: any) =>
11 | get({url: URL.list, params: params, data: {}, headers: {}});
12 | const createApi = async (data: any) =>
13 | post({
14 | url: URL.create,
15 | params: {},
16 | data: data,
17 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
18 | });
19 | const updateApi = async (params:any, data: any) =>
20 | post({
21 | url: URL.update,
22 | params: params,
23 | data: data,
24 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
25 | });
26 | const deleteApi = async (params: any) =>
27 | post({url: URL.delete, params: params, headers: {}});
28 |
29 | export {listApi, createApi, updateApi, deleteApi};
30 |
--------------------------------------------------------------------------------
/web/src/api/index/classification.ts:
--------------------------------------------------------------------------------
1 | import { get, post } from '/@/utils/http/axios';
2 | enum URL {
3 | list = '/myapp/index/classification/list',
4 | }
5 |
6 | const listApi = async (params: any) => get({ url: URL.list, params: params, data: {}, headers: {} });
7 |
8 | export { listApi};
9 |
--------------------------------------------------------------------------------
/web/src/api/index/comment.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | create = '/myapp/index/comment/create',
5 | listThingComments = '/myapp/index/comment/list',
6 | listUserComments = '/myapp/index/comment/listMyComments',
7 | like = '/myapp/index/comment/like'
8 | }
9 |
10 | const createApi = async (data: any) => post({
11 | url: URL.create,
12 | params: {},
13 | data: data,
14 | headers: {'Content-Type': 'multipart/form-data;charset=utf-8'}
15 | });
16 | const listThingCommentsApi = async (params: any) => get({url: URL.listThingComments, params: params, data: {}, headers: {}});
17 | const listUserCommentsApi = async (params: any) => get({url: URL.listUserComments, params: params, data: {}, headers: {}});
18 | const likeApi = async (params: any) => post({url: URL.like, params: params, headers: {}});
19 |
20 | export {createApi, listThingCommentsApi,listUserCommentsApi, likeApi};
21 |
--------------------------------------------------------------------------------
/web/src/api/index/company.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | listUserCompany = '/myapp/index/company/list_user_company_api',
7 | create = '/myapp/index/company/create',
8 | update = '/myapp/index/company/update',
9 | }
10 |
11 | const listUserCompanyApi = async (params: any) => get({ url: URL.listUserCompany, params: params, data: {}, headers: {} });
12 | const createApi = async (data: any) =>
13 | post({ url: URL.create, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
14 | const updateApi = async (params:any, data: any) =>
15 | post({ url: URL.update,params: params, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
16 |
17 | export { listUserCompanyApi, createApi, updateApi };
18 |
--------------------------------------------------------------------------------
/web/src/api/index/notice.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/index/notice/list_api',
5 | }
6 |
7 | const listApi = async (params: any) =>
8 | get({url: URL.list, params: params, data: {}, headers: {}});
9 |
10 | export {listApi};
11 |
--------------------------------------------------------------------------------
/web/src/api/index/order.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | create='/myapp/index/order/create',
5 | cancelUserOrder = '/myapp/index/order/cancel_order',
6 | userOrderList = '/myapp/index/order/list',
7 | }
8 |
9 | const createApi = async (data: any) =>
10 | post({url: URL.create, data: data, headers: {}});
11 |
12 | const userOrderListApi = async (params: any) =>
13 | get({url: URL.userOrderList, params: params, data: {}, headers: {}});
14 |
15 | const cancelUserOrderApi = async (params: any) =>
16 | post({url: URL.cancelUserOrder, params: params, headers: {}});
17 |
18 | export {createApi, userOrderListApi, cancelUserOrderApi};
19 |
--------------------------------------------------------------------------------
/web/src/api/index/post.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | listUserPostUrl = '/myapp/index/post/list_user_post_api',
7 | listCompanyPostUrl = '/myapp/index/post/list_company_post_api',
8 | create = '/myapp/index/post/create',
9 | }
10 |
11 | const listUserPostApi = async (params: any) => get({ url: URL.listUserPostUrl, params: params, data: {}, headers: {} });
12 | const listCompanyPostApi = async (params: any) => get({ url: URL.listCompanyPostUrl, params: params, data: {}, headers: {} });
13 | const createApi = async (data: any) =>
14 | post({ url: URL.create, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
15 |
16 | export { listUserPostApi, listCompanyPostApi, createApi };
17 |
--------------------------------------------------------------------------------
/web/src/api/index/resume.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | detail = '/myapp/index/resume/detail',
7 | create = '/myapp/index/resume/create',
8 | update = '/myapp/index/resume/update',
9 | }
10 |
11 | const detailApi = async (params: any) => get({ url: URL.detail, params: params, data: {}, headers: {} });
12 | const createApi = async (data: any) =>
13 | post({ url: URL.create, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
14 | const updateApi = async (params:any, data: any) =>
15 | post({ url: URL.update,params: params, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
16 |
17 | export { detailApi, createApi, updateApi };
18 |
--------------------------------------------------------------------------------
/web/src/api/index/tag.ts:
--------------------------------------------------------------------------------
1 | import {get, post} from '/@/utils/http/axios';
2 |
3 | enum URL {
4 | list = '/myapp/index/tag/list',
5 | }
6 |
7 | const listApi = async (params: any) =>
8 | get({url: URL.list, params: params, data: {}, headers: {}});
9 |
10 | export {listApi};
11 |
--------------------------------------------------------------------------------
/web/src/api/index/thing.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | list = '/myapp/index/thing/list',
7 | listUserThing = '/myapp/index/thing/list_user_thing',
8 | create = '/myapp/index/thing/create',
9 | update = '/myapp/index/thing/update',
10 | delete = '/myapp/index/thing/delete',
11 | detail = '/myapp/index/thing/detail',
12 | addWishUser = '/myapp/index/thing/addWishUser',
13 | addCollectUser = '/myapp/index/thing/addCollectUser',
14 | getCollectThingList = '/myapp/index/thing/getCollectThingList',
15 | getWishThingList = '/myapp/index/thing/getWishThingList',
16 | removeCollectUser = '/myapp/index/thing/removeCollectUser',
17 | removeWishUser = '/myapp/index/thing/removeWishUser'
18 | }
19 |
20 | const listApi = async (params: any) => get({ url: URL.list, params: params, data: {}, headers: {} });
21 | const listUserThingApi = async (params: any) => get({ url: URL.listUserThing, params: params, data: {}, headers: {} });
22 | const createApi = async (data:any) => post({ url: URL.create, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
23 | const updateApi = async (params: any, data:any) => post({ url: URL.update, params: params, data: data,headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
24 | const deleteApi = async (params: any) => post({ url: URL.delete, params: params, data: {}, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
25 | const detailApi = async (params: any) => get({ url: URL.detail, params: params, headers: {} });
26 | const addWishUserApi = async (params: any) => post({ url: URL.addWishUser, params: params, headers: {} });
27 | const addCollectUserApi = async (params: any) => post({ url: URL.addCollectUser, params: params, headers: {} });
28 | const getCollectThingListApi = async (params: any) => get({ url: URL.getCollectThingList, params: params, headers: {} });
29 | const getWishThingListApi = async (params: any) => get({ url: URL.getWishThingList, params: params, headers: {} });
30 |
31 | const removeCollectUserApi = async (params: any) => post({ url: URL.removeCollectUser, params: params, headers: {} });
32 | const removeWishUserApi = async (params: any) => post({ url: URL.removeWishUser, params: params, headers: {} });
33 |
34 |
35 | export { listApi,listUserThingApi, createApi,updateApi,deleteApi,detailApi, addWishUserApi,addCollectUserApi, getCollectThingListApi,
36 | getWishThingListApi, removeCollectUserApi, removeWishUserApi };
37 |
--------------------------------------------------------------------------------
/web/src/api/index/thingCollect.ts:
--------------------------------------------------------------------------------
1 |
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 |
5 | enum URL {
6 | userCollectList = '/api/thingCollect/getUserCollectList',
7 | collect = '/api/thingCollect/collect',
8 | unCollect = '/api/thingCollect/unCollect',
9 | }
10 |
11 | const collectApi = async (data: any) => post({ url: URL.collect, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
12 | const unCollectApi = async (params: any) => post({ url: URL.unCollect, params: params, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
13 | const userCollectListApi = async (params: any) => get({ url: URL.userCollectList, params: params });
14 |
15 | export { collectApi, unCollectApi, userCollectListApi };
16 |
--------------------------------------------------------------------------------
/web/src/api/index/thingWish.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | userWishList = '/api/thingWish/getUserWishList',
7 | wish = '/api/thingWish/wish',
8 | unWish = '/api/thingWish/unWish',
9 | }
10 |
11 | const wishApi = async (data: any) => post({ url: URL.wish, params: {}, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
12 | const unWishApi = async (params: any) => post({ url: URL.unWish, params: params, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
13 | const userWishListApi = async (params: any) => get({ url: URL.userWishList, params: params });
14 |
15 | export { wishApi, unWishApi, userWishListApi };
16 |
--------------------------------------------------------------------------------
/web/src/api/index/user.ts:
--------------------------------------------------------------------------------
1 | // 权限问题后期增加
2 | import { get, post } from '/@/utils/http/axios';
3 | import { UserState } from '/@/store/modules/user/types';
4 | // import axios from 'axios';
5 | enum URL {
6 | userLogin = '/myapp/index/user/login',
7 | userRegister = '/myapp/index/user/register',
8 | detail = '/myapp/index/user/info',
9 | updateUserPwd = '/myapp/index/user/updatePwd',
10 | updateUserInfo = '/myapp/index/user/update'
11 | }
12 | interface LoginRes {
13 | token: string;
14 | }
15 |
16 | export interface LoginData {
17 | username: string;
18 | password: string;
19 | }
20 |
21 | const detailApi = async (params: any) => get({ url: URL.detail, params: params, data: {}, headers: {} });
22 | const userLoginApi = async (data: LoginData) => post({ url: URL.userLogin, data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
23 | const userRegisterApi = async (data: any) => post({ url: URL.userRegister, params: {}, data: data });
24 | const updateUserPwdApi = async (params: any, data:any) => post({ url: URL.updateUserPwd, params: params, data:data });
25 | const updateUserInfoApi = async (params: any,data: any) => post({ url: URL.updateUserInfo, params:params, data: data, headers: { 'Content-Type': 'multipart/form-data;charset=utf-8' } });
26 |
27 | export { detailApi, userLoginApi, userRegisterApi, updateUserPwdApi, updateUserInfoApi};
28 |
--------------------------------------------------------------------------------
/web/src/assets/fonts/Blimone-ExtraBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/fonts/Blimone-ExtraBold.woff
--------------------------------------------------------------------------------
/web/src/assets/fonts/Blimone-ExtraLight.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/fonts/Blimone-ExtraLight.woff
--------------------------------------------------------------------------------
/web/src/assets/fonts/Blimone-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/fonts/Blimone-Light.woff
--------------------------------------------------------------------------------
/web/src/assets/fonts/Blimone-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/fonts/Blimone-Regular.woff
--------------------------------------------------------------------------------
/web/src/assets/icons/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/icons/logo.png
--------------------------------------------------------------------------------
/web/src/assets/icons/svg/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/assets/icons/svg/marks.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/assets/icons/svg/test.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/assets/icons/svg/ts.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/assets/icons/svg/twitter.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/assets/images/add.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/address-right-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/images/ali-pay-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/images/avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/images/avatar.jpg
--------------------------------------------------------------------------------
/web/src/assets/images/banner-02.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/images/banner-02.webp
--------------------------------------------------------------------------------
/web/src/assets/images/banner2.svg:
--------------------------------------------------------------------------------
1 |
49 |
--------------------------------------------------------------------------------
/web/src/assets/images/cart-icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/web/src/assets/images/clear-search.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/code-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/delete-icon.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/web/src/assets/images/ebook-download-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/ic-company.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/images/ic-company.png
--------------------------------------------------------------------------------
/web/src/assets/images/k-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/images/k-logo.png
--------------------------------------------------------------------------------
/web/src/assets/images/login-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/images/login-banner.png
--------------------------------------------------------------------------------
/web/src/assets/images/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/images/login.png
--------------------------------------------------------------------------------
/web/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/images/logo.png
--------------------------------------------------------------------------------
/web/src/assets/images/mail-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/message-icon.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/web/src/assets/images/order-address-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/order-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/images/order-point-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/order-thing-icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/web/src/assets/images/pwd-hidden.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/web/src/assets/images/pwd-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/qunerweima.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/images/qunerweima.jpg
--------------------------------------------------------------------------------
/web/src/assets/images/read-online-icon.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/web/src/assets/images/recommend-hover.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/web/src/assets/images/register-name.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/web/src/assets/images/search-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/images/searchIcon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/images/setting-card-icon.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/web/src/assets/images/setting-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/images/setting-msg-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/images/setting-push-icon.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/web/src/assets/images/setting-safe-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/share-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/web/src/assets/images/tel-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/images/want-read-hover.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/web/src/assets/images/wb-share.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/web/src/assets/images/wx-pay-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/styles/base.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeeeeeeek/python_job/570498312a91d5a1ea8f0988376bfc43f6bb6c0f/web/src/assets/styles/base.less
--------------------------------------------------------------------------------
/web/src/core/bootstrap.js:
--------------------------------------------------------------------------------
1 | // localStorage恢复到内存
2 |
3 | import {useUserStore} from "/@/store";
4 | import {USER_ID, USER_NAME, USER_TOKEN, ADMIN_USER_ID, ADMIN_USER_NAME, ADMIN_USER_TOKEN} from "/@/store/constants";
5 |
6 | export default function Initializer () {
7 | const userStore = useUserStore()
8 | userStore.$patch((state)=>{
9 | state.user_id = localStorage.getItem(USER_ID)
10 | state.user_name = localStorage.getItem(USER_NAME)
11 | state.user_token = localStorage.getItem(USER_TOKEN)
12 |
13 | state.admin_user_id = localStorage.getItem(ADMIN_USER_ID)
14 | state.admin_user_name = localStorage.getItem(ADMIN_USER_NAME)
15 | state.admin_user_token = localStorage.getItem(ADMIN_USER_TOKEN)
16 | console.log('恢复store完毕==>', state)
17 | })
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/web/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import App from './App.vue';
3 | import router from './router';
4 | import piniaStore from './store';
5 |
6 | import bootstrap from './core/bootstrap';
7 | import '/@/styles/reset.less';
8 | import '/@/styles/index.less';
9 | import Antd from 'ant-design-vue';
10 |
11 | const app = createApp(App);
12 |
13 |
14 | app.use(Antd);
15 | app.use(router);
16 | app.use(piniaStore);
17 | app.use(bootstrap)
18 | app.mount('#app');
19 |
--------------------------------------------------------------------------------
/web/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import {createRouter, createWebHistory} from 'vue-router';
2 | import root from './root';
3 |
4 | import { ADMIN_USER_TOKEN, USER_TOKEN } from '/@/store/constants'
5 |
6 | // 路由权限白名单
7 | const allowList = ['adminLogin', 'login', 'register', 'portal', 'search', 'detail', '403', '404']
8 | // 前台登录地址
9 | const loginRoutePath = '/index/login'
10 | // 后台登录地址
11 | const adminLoginRoutePath = '/adminLogin'
12 |
13 |
14 | const router = createRouter({
15 | history: createWebHistory(),
16 | routes: root,
17 | });
18 |
19 | router.beforeEach(async (to, from, next) => {
20 | console.log(to, from)
21 |
22 | /** 后台路由 **/
23 | if (to.path.startsWith('/admin')) {
24 | if (localStorage.getItem(ADMIN_USER_TOKEN)) {
25 | if (to.path === adminLoginRoutePath) {
26 | next({ path: '/' })
27 | } else {
28 | next()
29 | }
30 | } else {
31 | if (allowList.includes(to.name as string)) {
32 | // 在免登录名单,直接进入
33 | next()
34 | } else {
35 | next({ path: adminLoginRoutePath, query: { redirect: to.fullPath } })
36 | }
37 | }
38 | // next()
39 | }
40 |
41 | /** 前台路由 **/
42 | if (to.path.startsWith('/index')) {
43 | if (localStorage.getItem(USER_TOKEN)) {
44 | if (to.path === loginRoutePath) {
45 | next({ path: '/' })
46 | } else {
47 | next()
48 | }
49 | } else {
50 | if (allowList.includes(to.name as string)) {
51 | // 在免登录名单,直接进入
52 | next()
53 | } else {
54 | next({ path: loginRoutePath, query: { redirect: to.fullPath } })
55 | }
56 | }
57 | // next()
58 | }
59 |
60 | });
61 |
62 | router.afterEach((_to) => {
63 | // 回到顶部
64 | document.getElementById("html")?.scrollTo(0, 0)
65 | });
66 |
67 | export default router;
68 |
--------------------------------------------------------------------------------
/web/src/store/constants.ts:
--------------------------------------------------------------------------------
1 | const BASE_URL = 'http://127.0.0.1:8000'
2 | // const BASE_URL = 'http://124.221.83.178:9001'
3 |
4 | const USER_ID = 'user_id'
5 | const USER_NAME = 'user_name'
6 | const USER_TOKEN = 'user_token'
7 |
8 | const ADMIN_USER_ID = 'admin_user_id'
9 | const ADMIN_USER_NAME = 'admin_user_name'
10 | const ADMIN_USER_TOKEN = 'admin_user_token'
11 |
12 |
13 | export {BASE_URL, USER_TOKEN, USER_NAME, USER_ID, ADMIN_USER_ID,ADMIN_USER_NAME,ADMIN_USER_TOKEN }
14 |
--------------------------------------------------------------------------------
/web/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import { createPinia } from 'pinia';
2 | import { useAppStore } from './modules/app';
3 | import { useUserStore } from './modules/user';
4 |
5 | import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
6 |
7 | const pinia = createPinia();
8 | pinia.use(piniaPluginPersistedstate);
9 |
10 | export { useAppStore, useUserStore };
11 | export default pinia;
12 |
--------------------------------------------------------------------------------
/web/src/store/modules/app/index.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 | import piniaStore from '/@/store/index';
3 | import { AppState } from './types';
4 |
5 | export const useAppStore = defineStore(
6 | // 唯一ID
7 | 'app',
8 | {
9 | state: () => ({
10 | title: 'FastVue3, 一个快速开箱即用的Vue3+Vite模板',
11 | h1: 'Vue3 + Vite3.x + TypeScript + Pinia大厂开发必备',
12 | theme: '',
13 | }),
14 | getters: {},
15 | actions: {
16 | updateSettings(partial: Partial) {
17 | this.$patch(partial);
18 | },
19 |
20 | // Change theme color
21 | toggleTheme(dark: boolean) {
22 | if (dark) {
23 | this.theme = 'dark';
24 | document.documentElement.classList.add('dark');
25 | } else {
26 | this.theme = 'light';
27 | document.documentElement.classList.remove('dark');
28 | }
29 | },
30 | },
31 | persist: {
32 | key: 'theme',
33 | storage: localStorage,
34 | paths: ['theme'],
35 | },
36 | },
37 | );
38 |
39 | export function useAppOutsideStore() {
40 | return useAppStore(piniaStore);
41 | }
42 |
--------------------------------------------------------------------------------
/web/src/store/modules/app/types.ts:
--------------------------------------------------------------------------------
1 | export interface AppState {
2 | theme: string;
3 | colorWeek: boolean;
4 | navbar: boolean;
5 | menu: boolean;
6 | menuCollapse: boolean;
7 | footer: boolean;
8 | themeColor: string;
9 | menuWidth: number;
10 | globalSettings: boolean;
11 | [key: string]: unknown;
12 | }
13 |
--------------------------------------------------------------------------------
/web/src/store/modules/user/index.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 | import {loginApi as adminLogin} from '/@/api/admin/user';
3 | import {userLoginApi} from '/@/api/index/user';
4 | import { setToken, clearToken } from '/@/utils/auth';
5 | import { UserState } from './types';
6 | import {USER_ID, USER_NAME, USER_TOKEN, ADMIN_USER_ID,ADMIN_USER_NAME,ADMIN_USER_TOKEN} from "/@/store/constants";
7 |
8 | export const useUserStore = defineStore('user', {
9 | state: (): UserState => ({
10 | user_id: undefined,
11 | user_name: undefined,
12 | user_token: undefined,
13 |
14 | admin_user_id: undefined,
15 | admin_user_name: undefined,
16 | admin_user_token: undefined,
17 | }),
18 | getters: {},
19 | actions: {
20 | // 用户登录
21 | async login(loginForm) {
22 | const result = await userLoginApi(loginForm);
23 | console.log('result==>', result)
24 |
25 | if(result.code === 0) {
26 | this.$patch((state)=>{
27 | state.user_id = result.data.id
28 | state.user_name = result.data.username
29 | state.user_token = result.data.token
30 | console.log('state==>', state)
31 | })
32 |
33 | localStorage.setItem(USER_TOKEN, result.data.token)
34 | localStorage.setItem(USER_NAME, result.data.username)
35 | localStorage.setItem(USER_ID, result.data.id)
36 | }
37 |
38 | return result;
39 | },
40 | // 用户登出
41 | async logout() {
42 | // await userLogout();
43 | this.$patch((state)=>{
44 | localStorage.removeItem(USER_ID)
45 | localStorage.removeItem(USER_NAME)
46 | localStorage.removeItem(USER_TOKEN)
47 |
48 | state.user_id = undefined
49 | state.user_name = undefined
50 | state.user_token = undefined
51 | })
52 | },
53 |
54 | // 管理员登录
55 | async adminLogin(loginForm) {
56 | const result = await adminLogin(loginForm);
57 | console.log('result==>', result)
58 |
59 | if(result.code === 0) {
60 | this.$patch((state)=>{
61 | state.admin_user_id = result.data.id
62 | state.admin_user_name = result.data.username
63 | state.admin_user_token = result.data.admin_token
64 | console.log('state==>', state)
65 | })
66 |
67 | localStorage.setItem(ADMIN_USER_TOKEN, result.data.admin_token)
68 | localStorage.setItem(ADMIN_USER_NAME, result.data.username)
69 | localStorage.setItem(ADMIN_USER_ID, result.data.id)
70 | }
71 |
72 | return result;
73 | },
74 | // 管理员登出
75 | async adminLogout() {
76 | // await userLogout();
77 | this.$patch((state)=>{
78 | localStorage.removeItem(ADMIN_USER_ID)
79 | localStorage.removeItem(ADMIN_USER_NAME)
80 | localStorage.removeItem(ADMIN_USER_TOKEN)
81 |
82 | state.admin_user_id = undefined
83 | state.admin_user_name = undefined
84 | state.admin_user_token = undefined
85 | })
86 | },
87 | },
88 | });
89 |
--------------------------------------------------------------------------------
/web/src/store/modules/user/types.ts:
--------------------------------------------------------------------------------
1 | export type RoleType = '' | '*' | 'admin' | 'user';
2 | export interface UserState {
3 | user_id: any;
4 | user_name: any;
5 | user_token: any;
6 |
7 | admin_user_id: any;
8 | admin_user_name: any;
9 | admin_user_token: any;
10 | }
11 |
--------------------------------------------------------------------------------
/web/src/styles/index.less:
--------------------------------------------------------------------------------
1 | //自定义css
2 | a {
3 | color: #1890ff;
4 | }
5 |
--------------------------------------------------------------------------------
/web/src/styles/reset.less:
--------------------------------------------------------------------------------
1 | html {
2 | box-sizing: border-box;
3 | }
4 |
5 | *,
6 | ::before,
7 | ::after {
8 | margin: 0;
9 | padding: 0;
10 | box-sizing: inherit;
11 | }
12 |
13 |
14 | a:hover,
15 | a:link,
16 | a:visited,
17 | a:active {
18 | text-decoration: none;
19 | }
20 |
21 | ol,
22 | ul {
23 | list-style: none;
24 | }
25 |
26 | input,
27 | textarea {
28 | outline: none;
29 | border: none;
30 | resize: none;
31 | }
32 |
33 | body {
34 | font-size: 14px;
35 | font-weight: 400;
36 | }
37 |
--------------------------------------------------------------------------------
/web/src/utils/auth.ts:
--------------------------------------------------------------------------------
1 | const TokenKey = 'fast-token';
2 | const TokenPrefix = 'Bearer ';
3 | const isLogin = () => {
4 | return !!localStorage.getItem(TokenKey);
5 | };
6 | const getToken = () => {
7 | return localStorage.getItem(TokenKey);
8 | };
9 | const setToken = (token: string) => {
10 | localStorage.setItem(TokenKey, token);
11 | };
12 | const clearToken = () => {
13 | localStorage.removeItem(TokenKey);
14 | };
15 | export { TokenPrefix, isLogin, getToken, setToken, clearToken };
16 |
--------------------------------------------------------------------------------
/web/src/utils/http/axios/index.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios';
3 | import { showMessage } from './status';
4 | import { IResponse } from './type';
5 | import { getToken } from '/@/utils/auth';
6 | import { TokenPrefix } from '/@/utils/auth';
7 | import {ADMIN_USER_TOKEN, USER_TOKEN, BASE_URL} from '/@/store/constants'
8 |
9 | const service: AxiosInstance = axios.create({
10 | // baseURL: import.meta.env.BASE_URL + '',
11 | baseURL: BASE_URL + '',
12 | timeout: 15000,
13 | });
14 |
15 | // axios实例拦截请求
16 | service.interceptors.request.use(
17 | (config: InternalAxiosRequestConfig) => {
18 |
19 | config.headers.ADMINTOKEN = localStorage.getItem(ADMIN_USER_TOKEN)
20 | config.headers.TOKEN = localStorage.getItem(USER_TOKEN)
21 |
22 | return config;
23 | },
24 | (error: AxiosError) => {
25 | return Promise.reject(error);
26 | },
27 | );
28 |
29 | // axios实例拦截响应
30 | service.interceptors.response.use(
31 | (response: AxiosResponse) => {
32 | if(response.status == 200) {
33 | if(response.data.code == 0 || response.data.code == 200) {
34 | return response
35 | }else {
36 | return Promise.reject(response.data)
37 | }
38 | } else {
39 | return Promise.reject(response.data)
40 | }
41 | },
42 | // 请求失败
43 | (error: any) => {
44 | console.log(error.response.status)
45 | if(error.response.status == 404) {
46 | // todo
47 | } else if(error.response.status == 403) {
48 | // todo
49 | }
50 | return Promise.reject(error)
51 | },
52 | );
53 |
54 |
55 |
56 | const request = (config: AxiosRequestConfig): Promise => {
57 | const conf = config;
58 | return new Promise((resolve, reject) => {
59 | service.request>(conf).then((res: AxiosResponse) => {
60 | const data = res.data
61 | resolve(data as T);
62 | }).catch(err => {
63 | reject(err)
64 | });
65 | });
66 | };
67 |
68 | export function get(config: AxiosRequestConfig): Promise {
69 | return request({ ...config, method: 'GET' });
70 | }
71 |
72 | export function post(config: AxiosRequestConfig): Promise {
73 | return request({ ...config, method: 'POST' });
74 | }
75 |
76 | export default request;
77 |
78 | export type { AxiosInstance, AxiosResponse };
79 |
--------------------------------------------------------------------------------
/web/src/utils/http/axios/status.ts:
--------------------------------------------------------------------------------
1 | export const showMessage = (status: number | string): string => {
2 | let message = '';
3 | switch (status) {
4 | case 400:
5 | message = '请求错误(400)';
6 | break;
7 | case 401:
8 | message = '未授权,请重新登录(401)';
9 | break;
10 | case 403:
11 | message = '拒绝访问(403)';
12 | break;
13 | case 404:
14 | message = '请求出错(404)';
15 | break;
16 | case 408:
17 | message = '请求超时(408)';
18 | break;
19 | case 500:
20 | message = '服务器错误(500)';
21 | break;
22 | case 501:
23 | message = '服务未实现(501)';
24 | break;
25 | case 502:
26 | message = '网络错误(502)';
27 | break;
28 | case 503:
29 | message = '服务不可用(503)';
30 | break;
31 | case 504:
32 | message = '网络超时(504)';
33 | break;
34 | case 505:
35 | message = 'HTTP版本不受支持(505)';
36 | break;
37 | default:
38 | message = `连接出错(${status})!`;
39 | }
40 | return `${message},请检查网络或联系管理员!`;
41 | };
42 |
--------------------------------------------------------------------------------
/web/src/utils/http/axios/type.ts:
--------------------------------------------------------------------------------
1 | export interface RequestOptions {
2 | // Whether to process the request result
3 | isTransformResponse?: boolean;
4 | }
5 |
6 | // 返回res.data的interface
7 | export interface IResponse {
8 | code: number | string;
9 | result: T;
10 | message: string;
11 | status: string | number;
12 | }
13 |
14 | /**用户登录 */
15 | export interface ILogin {
16 | /** 账户名称 */
17 | username: string;
18 | /** 账户密码 */
19 | password: string;
20 | }
21 |
--------------------------------------------------------------------------------
/web/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | // import { resolve } from 'path';
2 | // const fs = require('fs');
3 | //
4 | // function pathResolve(dir: string) {
5 | // return resolve(process.cwd(), '.', dir);
6 | // }
7 | //
8 | // export const getFolder = (path: any) => {
9 | // const components: Array = [];
10 | // const files = fs.readdirSync(path);
11 | // files.forEach(function (item: string) {
12 | // const stat = fs.lstatSync(path + '/' + item);
13 | // if (stat.isDirectory() === true && item != 'components') {
14 | // components.push(path + '/' + item);
15 | // components.push(pathResolve(path + '/' + item));
16 | // }
17 | // });
18 | // return components;
19 | // };
20 |
21 | export function getFormatTime(dateTime,flag) {
22 | if(dateTime != null ) {
23 | //若传入的dateTime为字符串类型,需要进行转换成数值,若不是无需下面注释代码
24 | var time = parseInt(dateTime)
25 | var date = new Date(time);
26 | //获取年份
27 | var YY = date.getFullYear();
28 | //获取月份
29 | var MM = (date.getMonth() + 1 < 10 ? '0'+(date.getMonth() + 1) : date.getMonth() + 1);
30 | //获取日期
31 | var DD = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate());
32 | if(flag) { //flag为true,显示时分秒格式
33 | //获取小时
34 | var hh = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours());
35 | //获取分
36 | var mm = (date.getMinutes() < 10 ? '0'+date.getMinutes() : date.getMinutes());
37 | ///获取秒
38 | var ss = (date.getSeconds() < 10 ? '0'+date.getSeconds() : date.getSeconds());
39 | //返回时间格式: 2020-11-09 13:14:52
40 | return YY + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss;
41 | } else {
42 | //返回时间格式: 2020-11-09
43 | return YY + '-' + MM + '-' + DD;
44 | }
45 | } else {
46 | return "";
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/web/src/utils/result.ts:
--------------------------------------------------------------------------------
1 | import { Recoverable } from 'repl';
2 |
3 | // 返回统一格式的接口数据类型定义
4 | export function successResult(result: T, { message = 'Request success' } = {}) {
5 | return {
6 | code: 200,
7 | result,
8 | message,
9 | status: 'ok',
10 | };
11 | }
12 | export function errorResult(message = 'Request failed', { code = -1, result = null } = {}) {
13 | return {
14 | code,
15 | result,
16 | message,
17 | status: 'fail',
18 | };
19 | }
20 |
21 | //返回分页数据
22 | export function pageSuccessResult(page: number, pageSize: number, list: T[], { message = 'ok' } = {}) {
23 | const pageData = pagination(page, pageSize, list);
24 | return {
25 | ...successResult({
26 | items: pageData,
27 | total: list.length,
28 | }),
29 | message,
30 | };
31 | }
32 |
33 | // 封装分页数据
34 | export function pagination(pageNo: number, pageSize: number, array: T[]): T[] {
35 | const offset = (pageNo - 1) * Number(pageSize);
36 | const res =
37 | offset + Number(pageSize) >= array.length ? array.slice(offset, array.length) : array.slice(offset, offset + Number(pageSize));
38 | return res;
39 | }
40 |
41 | // 返回参数类型定义
42 | export interface requestParams {
43 | method: string;
44 | body: any;
45 | headers?: { authorization?: string };
46 | query: any;
47 | }
48 |
49 | /**
50 | * @name getRequestToken
51 | * @description 通过request数据中获取token,具体情况根据接口规范修改
52 | */
53 | export function getRequestToken({ headers }: requestParams): string | undefined {
54 | return headers?.authorization;
55 | }
56 |
--------------------------------------------------------------------------------
/web/src/views/index/components/footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
29 |
30 |
84 |
--------------------------------------------------------------------------------
/web/src/views/index/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
--------------------------------------------------------------------------------
/web/src/views/index/portal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
25 |
28 |
--------------------------------------------------------------------------------
/web/src/views/index/register.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 注册新账号
7 | 我要登录
8 |
9 |
10 |
20 |
30 |
40 |
45 |
46 |
47 |
48 |
49 |
88 |
89 |
211 |
--------------------------------------------------------------------------------
/web/src/views/index/search.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
17 |
18 |
25 |
--------------------------------------------------------------------------------
/web/src/views/index/user/collect-thing-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
我的收藏
4 |
5 |
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
86 |
196 |
--------------------------------------------------------------------------------
/web/src/views/index/user/comment-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
我的评论
4 |
5 |
25 |
26 |
27 |
28 |
29 |
70 |
156 |
--------------------------------------------------------------------------------
/web/src/views/index/user/fans-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
我的粉丝
4 |
5 |
6 |
7 |
![]()
8 |
9 |
Python_C
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
27 |
104 |
--------------------------------------------------------------------------------
/web/src/views/index/user/follow-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
我的关注
4 |
5 |
6 |
7 |
![]()
8 |
9 |
Python_C
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
28 |
105 |
--------------------------------------------------------------------------------
/web/src/views/index/user/message-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
我的消息
4 |
5 |
6 |
7 |
8 |
9 |
10 |

13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
{{ item.content }}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
57 |
144 |
--------------------------------------------------------------------------------
/web/src/views/index/user/modal/edit-address.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
113 |
114 |
117 |
--------------------------------------------------------------------------------
/web/src/views/index/user/push-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
推送设置
4 |
5 |
6 |
7 |
推送邮箱
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
80 |
184 |
--------------------------------------------------------------------------------
/web/src/views/index/user/score-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
35 |
68 |
--------------------------------------------------------------------------------
/web/src/views/index/user/security-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
帐号安全
4 |
5 |
6 |
23 |
24 |
25 |
26 |
32 |
38 |
44 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
100 |
198 |
--------------------------------------------------------------------------------
/web/src/views/index/usercenter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
37 |
59 |
--------------------------------------------------------------------------------
/web/stylelint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | plugins: ['stylelint-order'],
4 | extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
5 | customSyntax: 'postcss-html',
6 | rules: {
7 | 'function-no-unknown': null,
8 | 'selector-class-pattern': null,
9 | 'selector-pseudo-class-no-unknown': [
10 | true,
11 | {
12 | ignorePseudoClasses: ['global'],
13 | },
14 | ],
15 | 'selector-pseudo-element-no-unknown': [
16 | true,
17 | {
18 | ignorePseudoElements: ['v-deep'],
19 | },
20 | ],
21 | 'at-rule-no-unknown': [
22 | true,
23 | {
24 | ignoreAtRules: ['tailwind', 'apply', 'variants', 'responsive', 'screen', 'function', 'if', 'each', 'include', 'mixin'],
25 | },
26 | ],
27 | 'no-empty-source': null,
28 | 'string-quotes': null,
29 | 'named-grid-areas-no-invalid': null,
30 | 'unicode-bom': 'never',
31 | 'no-descending-specificity': null,
32 | 'font-family-no-missing-generic-family-keyword': null,
33 | 'declaration-colon-space-after': 'always-single-line',
34 | 'declaration-colon-space-before': 'never',
35 | // 'declaration-block-trailing-semicolon': 'always',
36 | 'rule-empty-line-before': [
37 | 'always',
38 | {
39 | ignore: ['after-comment', 'first-nested'],
40 | },
41 | ],
42 | 'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }],
43 | 'order/order': [
44 | [
45 | 'dollar-variables',
46 | 'custom-properties',
47 | 'at-rules',
48 | 'declarations',
49 | {
50 | type: 'at-rule',
51 | name: 'supports',
52 | },
53 | {
54 | type: 'at-rule',
55 | name: 'media',
56 | },
57 | 'rules',
58 | ],
59 | { severity: 'warning' },
60 | ],
61 | },
62 | ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'],
63 | overrides: [
64 | {
65 | files: ['*.vue', '**/*.vue', '*.html', '**/*.html'],
66 | extends: ['stylelint-config-recommended'],
67 | rules: {
68 | 'keyframes-name-pattern': null,
69 | 'selector-pseudo-class-no-unknown': [
70 | true,
71 | {
72 | ignorePseudoClasses: ['deep', 'global'],
73 | },
74 | ],
75 | 'selector-pseudo-element-no-unknown': [
76 | true,
77 | {
78 | ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'],
79 | },
80 | ],
81 | },
82 | },
83 | {
84 | files: ['*.less', '**/*.less'],
85 | customSyntax: 'postcss-less',
86 | extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'],
87 | },
88 | ],
89 | };
90 |
--------------------------------------------------------------------------------
/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "moduleResolution": "node",
6 | "strict": true,
7 | "noLib": false,
8 | "forceConsistentCasingInFileNames": true,
9 | "allowSyntheticDefaultImports": true,
10 | "strictFunctionTypes": false,
11 | "jsx": "preserve",
12 | "baseUrl": ".",
13 | "allowJs": true,
14 | "sourceMap": true,
15 | "esModuleInterop": true,
16 | "resolveJsonModule": true,
17 | "noUnusedLocals": false,
18 | "noUnusedParameters": false,
19 | "experimentalDecorators": true,
20 | "lib": ["dom", "esnext"],
21 | "noImplicitAny": false,
22 | "skipLibCheck": true,
23 | "types": ["vite/client"],
24 | "removeComments": true,
25 | "paths": {
26 | "/@/*": ["src/*"],
27 | "/#/*": ["types/*"]
28 | }
29 | },
30 | "include": [
31 | "tests/**/*.ts",
32 | "src/**/*.ts",
33 | "src/**/*.d.ts",
34 | "src/**/*.tsx",
35 | "src/**/*.vue",
36 | "types/**/*.d.ts",
37 | "types/**/*.ts",
38 | "build/**/*.ts",
39 | "build/**/*.d.ts",
40 | "mock/**/*.ts",
41 | "vite.config.ts"
42 | ],
43 | "exclude": ["node_modules", "tests/server/**/*.ts", "dist", "**/*.js"]
44 | }
45 |
--------------------------------------------------------------------------------
/web/types/auto-imports.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by 'unplugin-auto-import'
2 | export {}
3 | declare global {
4 | const EffectScope: typeof import('vue')['EffectScope']
5 | const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
6 | const computed: typeof import('vue')['computed']
7 | const createApp: typeof import('vue')['createApp']
8 | const createPinia: typeof import('pinia')['createPinia']
9 | const customRef: typeof import('vue')['customRef']
10 | const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
11 | const defineComponent: typeof import('vue')['defineComponent']
12 | const defineStore: typeof import('pinia')['defineStore']
13 | const effectScope: typeof import('vue')['effectScope']
14 | const getActivePinia: typeof import('pinia')['getActivePinia']
15 | const getCurrentInstance: typeof import('vue')['getCurrentInstance']
16 | const getCurrentScope: typeof import('vue')['getCurrentScope']
17 | const h: typeof import('vue')['h']
18 | const inject: typeof import('vue')['inject']
19 | const isProxy: typeof import('vue')['isProxy']
20 | const isReactive: typeof import('vue')['isReactive']
21 | const isReadonly: typeof import('vue')['isReadonly']
22 | const isRef: typeof import('vue')['isRef']
23 | const mapActions: typeof import('pinia')['mapActions']
24 | const mapGetters: typeof import('pinia')['mapGetters']
25 | const mapState: typeof import('pinia')['mapState']
26 | const mapStores: typeof import('pinia')['mapStores']
27 | const mapWritableState: typeof import('pinia')['mapWritableState']
28 | const markRaw: typeof import('vue')['markRaw']
29 | const nextTick: typeof import('vue')['nextTick']
30 | const onActivated: typeof import('vue')['onActivated']
31 | const onBeforeMount: typeof import('vue')['onBeforeMount']
32 | const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
33 | const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
34 | const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
35 | const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
36 | const onDeactivated: typeof import('vue')['onDeactivated']
37 | const onErrorCaptured: typeof import('vue')['onErrorCaptured']
38 | const onMounted: typeof import('vue')['onMounted']
39 | const onRenderTracked: typeof import('vue')['onRenderTracked']
40 | const onRenderTriggered: typeof import('vue')['onRenderTriggered']
41 | const onScopeDispose: typeof import('vue')['onScopeDispose']
42 | const onServerPrefetch: typeof import('vue')['onServerPrefetch']
43 | const onUnmounted: typeof import('vue')['onUnmounted']
44 | const onUpdated: typeof import('vue')['onUpdated']
45 | const provide: typeof import('vue')['provide']
46 | const reactive: typeof import('vue')['reactive']
47 | const readonly: typeof import('vue')['readonly']
48 | const ref: typeof import('vue')['ref']
49 | const resolveComponent: typeof import('vue')['resolveComponent']
50 | const resolveDirective: typeof import('vue')['resolveDirective']
51 | const setActivePinia: typeof import('pinia')['setActivePinia']
52 | const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
53 | const shallowReactive: typeof import('vue')['shallowReactive']
54 | const shallowReadonly: typeof import('vue')['shallowReadonly']
55 | const shallowRef: typeof import('vue')['shallowRef']
56 | const storeToRefs: typeof import('pinia')['storeToRefs']
57 | const toRaw: typeof import('vue')['toRaw']
58 | const toRef: typeof import('vue')['toRef']
59 | const toRefs: typeof import('vue')['toRefs']
60 | const triggerRef: typeof import('vue')['triggerRef']
61 | const unref: typeof import('vue')['unref']
62 | const useAttrs: typeof import('vue')['useAttrs']
63 | const useCssModule: typeof import('vue')['useCssModule']
64 | const useCssVars: typeof import('vue')['useCssVars']
65 | const useDialog: typeof import('naive-ui')['useDialog']
66 | const useLink: typeof import('vue-router')['useLink']
67 | const useLoadingBar: typeof import('naive-ui')['useLoadingBar']
68 | const useMessage: typeof import('naive-ui')['useMessage']
69 | const useNotification: typeof import('naive-ui')['useNotification']
70 | const useRoute: typeof import('vue-router')['useRoute']
71 | const useRouter: typeof import('vue-router')['useRouter']
72 | const useSlots: typeof import('vue')['useSlots']
73 | const watch: typeof import('vue')['watch']
74 | const watchEffect: typeof import('vue')['watchEffect']
75 | const watchPostEffect: typeof import('vue')['watchPostEffect']
76 | const watchSyncEffect: typeof import('vue')['watchSyncEffect']
77 | }
78 |
--------------------------------------------------------------------------------
/web/types/components.d.ts:
--------------------------------------------------------------------------------
1 | // generated by unplugin-vue-components
2 | // We suggest you to commit this file into source control
3 | // Read more: https://github.com/vuejs/core/pull/3399
4 | import '@vue/runtime-core'
5 |
6 | export {}
7 |
8 | declare module '@vue/runtime-core' {
9 | export interface GlobalComponents {
10 | AButton: typeof import('ant-design-vue/es')['Button']
11 | ACard: typeof import('ant-design-vue/es')['Card']
12 | ACol: typeof import('ant-design-vue/es')['Col']
13 | AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
14 | ADescriptions: typeof import('ant-design-vue/es')['Descriptions']
15 | ADescriptionsItem: typeof import('ant-design-vue/es')['DescriptionsItem']
16 | ADivider: typeof import('ant-design-vue/es')['Divider']
17 | ADrawer: typeof import('ant-design-vue/es')['Drawer']
18 | ADropdown: typeof import('ant-design-vue/es')['Dropdown']
19 | AForm: typeof import('ant-design-vue/es')['Form']
20 | AFormItem: typeof import('ant-design-vue/es')['FormItem']
21 | AInput: typeof import('ant-design-vue/es')['Input']
22 | AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
23 | AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
24 | AInputSearch: typeof import('ant-design-vue/es')['InputSearch']
25 | ALayout: typeof import('ant-design-vue/es')['Layout']
26 | ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
27 | ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
28 | ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
29 | AMenu: typeof import('ant-design-vue/es')['Menu']
30 | AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
31 | AModal: typeof import('ant-design-vue/es')['Modal']
32 | APagination: typeof import('ant-design-vue/es')['Pagination']
33 | APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
34 | ARow: typeof import('ant-design-vue/es')['Row']
35 | ASelect: typeof import('ant-design-vue/es')['Select']
36 | ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
37 | ASpace: typeof import('ant-design-vue/es')['Space']
38 | ASpin: typeof import('ant-design-vue/es')['Spin']
39 | ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
40 | ASwitch: typeof import('ant-design-vue/es')['Switch']
41 | ATable: typeof import('ant-design-vue/es')['Table']
42 | ATabPane: typeof import('ant-design-vue/es')['TabPane']
43 | ATabs: typeof import('ant-design-vue/es')['Tabs']
44 | ATag: typeof import('ant-design-vue/es')['Tag']
45 | ATextarea: typeof import('ant-design-vue/es')['Textarea']
46 | ATree: typeof import('ant-design-vue/es')['Tree']
47 | ATreeSelect: typeof import('ant-design-vue/es')['TreeSelect']
48 | ATreeSelectNode: typeof import('ant-design-vue/es')['TreeSelectNode']
49 | AUpload: typeof import('ant-design-vue/es')['Upload']
50 | AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger']
51 | RouterLink: typeof import('vue-router')['RouterLink']
52 | RouterView: typeof import('vue-router')['RouterView']
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/web/types/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.vue' {
4 | import { DefineComponent } from 'vue';
5 | const component: DefineComponent<{}, {}, any>;
6 | export default component;
7 | }
8 |
9 | declare module 'virtual:*' {
10 | const result: any;
11 | export default result;
12 | }
13 |
--------------------------------------------------------------------------------
/web/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { UserConfig, ConfigEnv } from 'vite';
2 | import { createVitePlugins } from './build/vite/plugins';
3 | import { resolve } from 'path';
4 | import { VITE_PORT } from './build/constant';
5 |
6 | function pathResolve(dir: string) {
7 | return resolve(process.cwd(), '.', dir);
8 | }
9 |
10 | // https://vitejs.dev/config/
11 | export default ({ command }: ConfigEnv): UserConfig => {
12 | const isBuild = command === 'build';
13 | let base: string;
14 | if (command === 'build') {
15 | base = '/';
16 | } else {
17 | base = '/';
18 | }
19 | return {
20 | base,
21 | publicDir: "public", //静态资源服务的文件夹
22 | resolve: {
23 | alias: [
24 | {
25 | find: 'vue-i18n',
26 | replacement: 'vue-i18n/dist/vue-i18n.cjs.js',
27 | },
28 | // 别名 /@/xxxx => src/xxxx
29 | {
30 | find: '/@',
31 | replacement: pathResolve('src') + '/',
32 | },
33 | ],
34 | },
35 | // plugins
36 | plugins: createVitePlugins(isBuild),
37 |
38 | // css
39 | css: {},
40 |
41 | // server
42 | server: {
43 | hmr: { overlay: false }, // 禁用或配置 HMR 连接 设置 server.hmr.overlay 为 false 可以禁用服务器错误遮罩层
44 | // 服务配置
45 | port: VITE_PORT, // 类型: number 指定服务器端口;
46 | open: false, // 类型: boolean | string在服务器启动时自动在浏览器中打开应用程序;
47 | cors: true, // 类型: boolean | CorsOptions 为开发服务器配置 CORS。默认启用并允许任何源
48 | host: '0.0.0.0', // IP配置,支持从IP启动
49 | https: false, // 禁用https
50 | // proxy,
51 | },
52 | };
53 | };
54 |
--------------------------------------------------------------------------------
《{{item.title}}》
14 |