├── .gitignore ├── .vscode └── extensions.json ├── README.md ├── index.html ├── package.json ├── pnpm-lock.yaml ├── public └── vite.svg ├── src ├── App.vue ├── api │ ├── api.js │ ├── config │ │ └── index.js │ └── request.js ├── assets │ ├── docs │ │ ├── img.png │ │ ├── img_1.png │ │ ├── img_2.png │ │ ├── img_3.png │ │ ├── img_4.png │ │ ├── img_5.png │ │ ├── img_6.png │ │ ├── img_7.png │ │ ├── img_8.png │ │ ├── img_9.png │ │ └── preview.png │ ├── style │ │ ├── global.css │ │ ├── mixin.less │ │ ├── reset.css │ │ └── variable.less │ └── vue.svg ├── components │ ├── Bytedance-Button.vue │ ├── Checkbox-Transfer.vue │ ├── File-Icon.vue │ ├── HelloWorld.vue │ ├── Input-Search.vue │ ├── Loading │ │ ├── Loading.vue │ │ └── index.js │ ├── Logo.vue │ ├── Pagination.vue │ ├── footer.vue │ ├── header.vue │ ├── message │ │ ├── index.js │ │ └── main.vue │ └── popup-progress │ │ ├── index.js │ │ └── main.vue ├── helper │ ├── EventBus │ │ └── index.js │ └── utilities.js ├── main.js ├── router │ └── index.js ├── store │ └── index.js ├── test │ └── test.js └── views │ ├── Home │ └── Home.vue │ ├── JobDetail │ └── JobDetail.vue │ ├── Jobs │ └── Jobs.vue │ ├── Login │ └── Login.vue │ ├── Products │ └── Products.vue │ ├── StaffStories │ └── StaffStories.vue │ ├── Test │ └── index.vue │ └── User │ └── User.vue └── vite.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Vite 2 | 3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 ` 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "byte", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@element-plus/icons-vue": "^2.1.0", 13 | "axios": "^1.4.0", 14 | "element-plus": "^2.3.4", 15 | "mitt": "^3.0.0", 16 | "nprogress": "^0.2.0", 17 | "sass": "^1.62.1", 18 | "sass-loader": "^13.2.2", 19 | "vue": "^3.2.47", 20 | "vue-router": "^4.1.6", 21 | "vuex": "^4.1.0" 22 | }, 23 | "devDependencies": { 24 | "@vitejs/plugin-vue": "^4.1.0", 25 | "less": "^4.1.3", 26 | "less-loader": "^11.1.0", 27 | "unplugin-auto-import": "^0.15.3", 28 | "unplugin-vue-components": "^0.24.1", 29 | "vite": "^4.3.2" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 82 | 83 | 146 | -------------------------------------------------------------------------------- /src/api/api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 项目总api管理 3 | */ 4 | import request from "./request.js"; 5 | 6 | export default { 7 | // 登录 8 | login: (data) => request({ 9 | url: '/login/', 10 | method: 'post', 11 | data: data 12 | }), 13 | 14 | // 注册 15 | sign: (data) => request({ 16 | url: '/sign/', 17 | method: 'post', 18 | data: data 19 | }), 20 | 21 | // 获取产品列表 22 | getProductList: (data) => request({ 23 | url: '/product/', 24 | method: 'get', 25 | data: data 26 | }), 27 | 28 | // 获取岗位种类 29 | getCategory: () => request({ 30 | url: '/category/', 31 | method: 'get', 32 | }), 33 | 34 | // 获取城市列表 35 | getCity: () => request({ 36 | url: '/city/', 37 | method: 'get', 38 | }), 39 | 40 | // 获取岗位信息 41 | getJobList: (data) => request({ 42 | url: '/job/', 43 | method: 'post', 44 | data: data, 45 | }), 46 | 47 | // 获取某个岗位详情 48 | getJobDetail: (id) => request({ 49 | url: `/job_detail/${id}`, 50 | method: 'get', 51 | }), 52 | 53 | testAPI: (data) => { 54 | console.log(data, typeof data) 55 | return request({ 56 | url: '/test/', 57 | method: 'post', 58 | data 59 | }) 60 | } 61 | } -------------------------------------------------------------------------------- /src/api/config/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 环境配置文件 3 | * 开发环境 4 | * 生产环境 5 | * 测试环境 6 | */ 7 | 8 | // 拿到当前环境 9 | const env = import.meta.env.MODE || 'development' 10 | 11 | const EnvConfig = { 12 | development: { 13 | baseApi: 'http://127.0.0.1:8000/api', 14 | mockApi: 'https://www.fastmock.site/mock/3945196801b2b17aeb94fb84612b796a/api' 15 | }, 16 | 17 | test: { 18 | baseApi: '//test.future.com/api', 19 | mockApi: 'https://www.fastmock.site/mock/3945196801b2b17aeb94fb84612b796a/api' 20 | }, 21 | 22 | production: { 23 | baseApi: '//production.future.com/api', 24 | mockApi: 'https://www.fastmock.site/mock/3945196801b2b17aeb94fb84612b796a/api' 25 | }, 26 | } 27 | 28 | export default { 29 | env, 30 | // mock总开关 31 | mock: false, 32 | ...EnvConfig[env] 33 | } -------------------------------------------------------------------------------- /src/api/request.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import config from "./config/index.js"; 3 | 4 | // 引入进度条 5 | import nprogress from 'nprogress' 6 | 7 | // 引入nprogress的css样式 8 | import 'nprogress/nprogress.css' 9 | import store from "../store/index.js"; 10 | 11 | const NETWORK_ERROR = '网络请求异常,后端未开启,请稍后重试......' 12 | 13 | // 创建一个axios实例对象 14 | const service = axios.create({ 15 | baseURL: config.baseApi, 16 | 17 | // 超时时间 18 | timeout: 5000 19 | }) 20 | 21 | // 请求拦截器 22 | service.interceptors.request.use((request) => { 23 | // 自定义headers 24 | // 如果有userid,在请求头中添加 25 | if (store.state.userid) { 26 | request.headers.userid = store.state.userid 27 | } 28 | 29 | // jwt-token认证 30 | // 如果有token,在请求头中添加 31 | if (store.state.token) { 32 | request.headers.token = store.state.token 33 | } 34 | 35 | nprogress.start() 36 | return request 37 | }) 38 | 39 | // 响应拦截器 40 | service.interceptors.response.use((response) => { 41 | nprogress.done() 42 | const {code, data, msg} = response.data 43 | if (code === 200) { 44 | return response.data 45 | } else { 46 | // 请求错误,返回错误信息 47 | ElMessage.error(msg || NETWORK_ERROR) 48 | return Promise.reject(msg || NETWORK_ERROR) 49 | } 50 | }) 51 | 52 | // 封装的核心函数 53 | function request(options) { 54 | options.method = options.method || 'get' 55 | if (options.method.toLowerCase() === 'get') { 56 | options.params = options.data 57 | } 58 | 59 | // 对mock的处理 60 | let isMock = config.mock 61 | if (typeof options.mock !== 'undefined') { 62 | isMock = options.mock 63 | } 64 | 65 | // 对线上环境的处理 66 | if (config.env === 'production') { 67 | // 拒绝使用mock 68 | service.defaults.baseURL = config.baseApi 69 | } else { 70 | service.defaults.baseURL = isMock? config.mockApi : config.baseApi 71 | } 72 | 73 | return service(options) 74 | } 75 | 76 | export default request 77 | -------------------------------------------------------------------------------- /src/assets/docs/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img.png -------------------------------------------------------------------------------- /src/assets/docs/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_1.png -------------------------------------------------------------------------------- /src/assets/docs/img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_2.png -------------------------------------------------------------------------------- /src/assets/docs/img_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_3.png -------------------------------------------------------------------------------- /src/assets/docs/img_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_4.png -------------------------------------------------------------------------------- /src/assets/docs/img_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_5.png -------------------------------------------------------------------------------- /src/assets/docs/img_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_6.png -------------------------------------------------------------------------------- /src/assets/docs/img_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_7.png -------------------------------------------------------------------------------- /src/assets/docs/img_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_8.png -------------------------------------------------------------------------------- /src/assets/docs/img_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/img_9.png -------------------------------------------------------------------------------- /src/assets/docs/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meetSeparate/byteDance-Vue3/97df4451e5fe1c7f3642e3e997e7e9c4e9174e8a/src/assets/docs/preview.png -------------------------------------------------------------------------------- /src/assets/style/global.css: -------------------------------------------------------------------------------- 1 | .clearfix::before, 2 | .clearfix::after { 3 | content: ""; 4 | display: table; 5 | height: 0; 6 | clear: both; 7 | } 8 | 9 | 10 | *{ 11 | user-select: none; 12 | text-decoration: none; 13 | } -------------------------------------------------------------------------------- /src/assets/style/mixin.less: -------------------------------------------------------------------------------- 1 | .text-overflow-visible-line(@num) { 2 | -webkit-box-orient: vertical; 3 | display: -webkit-box; 4 | -webkit-line-clamp: @num; 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/style/reset.css: -------------------------------------------------------------------------------- 1 | ul, 2 | li { 3 | list-style: none; 4 | /* padding:0; */ 5 | /* margin:0; */ 6 | } 7 | div, 8 | ul, 9 | li, 10 | dl, 11 | dd, 12 | dt, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | h6, 19 | header, 20 | main, 21 | section, 22 | aside, 23 | body { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | *, 28 | *:after, 29 | *:before { 30 | box-sizing: border-box; 31 | } 32 | a:-webkit-any-link { 33 | color: inherit; 34 | text-decoration: none; 35 | } 36 | *:focus, 37 | input:focus, 38 | textarea:focus { 39 | outline: none; 40 | } 41 | 42 | textarea, 43 | input[type="text"], 44 | input[type="password"] { 45 | border-style: solid; 46 | font-weight: 300; 47 | outline: none; 48 | border-width: 1px; 49 | border-color: #dcdfe6; 50 | font-size: inherit; 51 | line-height: inherit; 52 | } 53 | 54 | 55 | 56 | /* custom */ 57 | -------------------------------------------------------------------------------- /src/assets/style/variable.less: -------------------------------------------------------------------------------- 1 | @main-color: #3370ff; 2 | @main-width: 1300px; 3 | 4 | @primary-text-color: #1f2329; 5 | @regular-text-color: #606266; 6 | @secondary-text-color: #909399; 7 | 8 | @border-dark-color: #34373b; 9 | @border-base-color: #dcdfe6; 10 | @border-light-color: #e4e7ed; 11 | @border-lighter-color: #ebeef5; 12 | @border-extralight-color: #f2f6fc; 13 | 14 | @bg-white-color: #fff; 15 | @bg-black-color: #000; 16 | @bg-base-color: #f5f7fa; 17 | 18 | @font-size-larger: 32px; 19 | @font-size-large: 22px; 20 | @font-size-medium: 18px; 21 | @font-size-base: 14px; 22 | @font-size-small: 12px; 23 | 24 | @font-weight-primary: 700; 25 | @font-weight-regular: 400; 26 | @font-weight-secondary: 100; 27 | 28 | @font-line-height-large: 32px; 29 | @font-line-height-primary: 24px; 30 | @font-line-height-secondary: 18px; 31 | 32 | @box-shadow-hover-color: rgba(136, 150, 171, 0.15); 33 | @box-shadow-dark-color: rgba(136, 150, 171, 0.5); 34 | -------------------------------------------------------------------------------- /src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Bytedance-Button.vue: -------------------------------------------------------------------------------- 1 | 15 | 33 | 70 | -------------------------------------------------------------------------------- /src/components/Checkbox-Transfer.vue: -------------------------------------------------------------------------------- 1 | 43 | 159 | 236 | -------------------------------------------------------------------------------- /src/components/File-Icon.vue: -------------------------------------------------------------------------------- 1 | 98 | 99 | 105 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 35 | 36 | 41 | -------------------------------------------------------------------------------- /src/components/Input-Search.vue: -------------------------------------------------------------------------------- 1 | 11 | 14 | 15 | 112 | -------------------------------------------------------------------------------- /src/components/Loading/Loading.vue: -------------------------------------------------------------------------------- 1 | 3 | 4 | 17 | 18 | 105 | -------------------------------------------------------------------------------- /src/components/Loading/index.js: -------------------------------------------------------------------------------- 1 | import {createVNode, render} from 'vue' 2 | import Loading from './Loading.vue' 3 | 4 | export default { 5 | install(app) { 6 | const VNode = createVNode(Loading) 7 | render(VNode, document.body) 8 | }, 9 | show() { 10 | const loading = document.getElementById('loading') 11 | loading.style.display = 'block' 12 | }, 13 | close() { 14 | const loading = document.getElementById('loading') 15 | loading.style.display = 'none' 16 | } 17 | } -------------------------------------------------------------------------------- /src/components/Logo.vue: -------------------------------------------------------------------------------- 1 | 197 | 211 | -------------------------------------------------------------------------------- /src/components/Pagination.vue: -------------------------------------------------------------------------------- 1 | 34 | 104 | 129 | -------------------------------------------------------------------------------- /src/components/footer.vue: -------------------------------------------------------------------------------- 1 | 225 | 227 | 269 | -------------------------------------------------------------------------------- /src/components/header.vue: -------------------------------------------------------------------------------- 1 | 68 | 106 | 308 | -------------------------------------------------------------------------------- /src/components/message/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Message from "./main"; 3 | import { defaults } from "./main"; 4 | import { pick } from "@/helper/utilities.js"; 5 | const MessageCtor = Vue.extend(Message); 6 | 7 | const queue = []; 8 | let index = 0; 9 | 10 | MessageCtor.prototype.close = function() { 11 | this.$destroy(); 12 | this.$el.addEventListener("animationend", () => { 13 | this.$el.remove(); 14 | }); 15 | 16 | let targetIndex = queue.indexOf(this); 17 | let removedHeight = this.$el.offsetHeight; 18 | 19 | if (targetIndex < 0) return; 20 | for (let i = targetIndex + 1; i < queue.length; i++) { 21 | const dom = queue[i].$el; 22 | dom.style.top = parseInt(dom.style.top, 10) - removedHeight + 13 + "px"; 23 | } 24 | queue.splice(targetIndex, 1); 25 | }; 26 | 27 | export default function createMessage(opts = {}) { 28 | const instance = new MessageCtor({ data: pick(opts, Object.keys(defaults)) }); 29 | instance.index = ++index; 30 | instance.$mount(); 31 | queue.forEach((item) => { 32 | instance.offsetTop += item.$el.offsetHeight + 13; 33 | }); 34 | queue.push(instance); 35 | 36 | document.body.appendChild(instance.$el); 37 | setTimeout(() => { 38 | instance.close(); 39 | }, instance.duration); 40 | return instance; 41 | } 42 | createMessage.install = (Vue) => { 43 | Vue.prototype.$message = createMessage; 44 | 45 | ["warning", "error", "success"].forEach((type) => { 46 | createMessage[type] = function(opts = {}) { 47 | if (typeof opts === "string") { 48 | opts = { 49 | message: opts, 50 | }; 51 | } 52 | opts.type = type; 53 | return createMessage(opts); 54 | }; 55 | }); 56 | }; 57 | -------------------------------------------------------------------------------- /src/components/message/main.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 47 | 48 | 129 | -------------------------------------------------------------------------------- /src/components/popup-progress/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Progressbar from "./main.vue"; 3 | 4 | let singleProgress; 5 | const ProgressbarCtor = Vue.extend(Progressbar); 6 | ProgressbarCtor.prototype.close = function() { 7 | singleProgress = null; 8 | this.visible = false; 9 | this.value = 0; 10 | 11 | this.$nextTick(() => { 12 | this.$destroy(); 13 | }); 14 | }; 15 | 16 | function pick(obj = {}, keys = []) { 17 | const result = {}; 18 | keys.forEach((key) => { 19 | result[key] = obj[key]; 20 | }); 21 | return result; 22 | } 23 | 24 | function createPopupProgress(opts = {}) { 25 | if (singleProgress) return singleProgress; 26 | 27 | singleProgress = new ProgressbarCtor({ 28 | data: pick(opts, Object.keys(opts)), 29 | }); 30 | 31 | singleProgress.$mount(); 32 | document.body.appendChild(singleProgress.$el); 33 | 34 | singleProgress.visible = true; 35 | return singleProgress; 36 | } 37 | 38 | export default { 39 | install(Vue) { 40 | Vue.prototype.$popupProgress = createPopupProgress; 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /src/components/popup-progress/main.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 55 | 56 | 130 | -------------------------------------------------------------------------------- /src/helper/EventBus/index.js: -------------------------------------------------------------------------------- 1 | import mitt from "mitt"; 2 | 3 | export default mitt() -------------------------------------------------------------------------------- /src/helper/utilities.js: -------------------------------------------------------------------------------- 1 | export const watchScrollDirection = function(scrollElement, callback) { 2 | const scrollPos = { x: 0, y: 0 }; 3 | const scrollDirection = { 4 | directionX: 1, 5 | directionY: 1, 6 | }; 7 | let previousTimer; 8 | function onScroll(e) { 9 | const scrollTop = scrollElement.scrollTop || scrollElement.pageYOffset; 10 | const scrollLeft = scrollElement.scrollLeft || scrollElement.pageXOffset; 11 | 12 | if (scrollPos.y > scrollTop) { 13 | scrollDirection.directionY = -1; 14 | } else { 15 | scrollDirection.directionY = 1; 16 | } 17 | if (scrollPos.x > scrollLeft) { 18 | scrollDirection.directionX = -1; 19 | } else { 20 | scrollDirection.directionX = 1; 21 | } 22 | 23 | callback.call(scrollElement, scrollDirection, scrollPos); 24 | 25 | scrollPos.x = scrollLeft; 26 | scrollPos.y = scrollTop; 27 | } 28 | function throttle() { 29 | let now = Date.now(); 30 | if (!previousTimer) previousTimer = now; 31 | if (now - previousTimer > 30) { 32 | onScroll(); 33 | previousTimer = now; 34 | } 35 | } 36 | scrollElement.addEventListener("scroll", throttle); 37 | return function() { 38 | scrollElement.removeEventListener("scroll", throttle); 39 | }; 40 | }; 41 | 42 | export function formatDate(date, format = true) { 43 | date = new Date(date); 44 | if (Number.isNaN(date.getTime())) { 45 | return false; 46 | } 47 | 48 | const Y = date.getFullYear(); 49 | const M = (parseInt(date.getMonth()) + 1).toString().padStart(2, 0); 50 | const d = date 51 | .getDate() 52 | .toString() 53 | .padStart(2, 0); 54 | const h = date 55 | .getHours() 56 | .toString() 57 | .padStart(2, 0); 58 | const m = date 59 | .getMinutes() 60 | .toString() 61 | .padStart(2, 0); 62 | const s = date 63 | .getSeconds() 64 | .toString() 65 | .padStart(2, 0); 66 | 67 | return format ? `${Y}-${M}-${d} ${h}:${m}:${s}` : `${Y}-${M}-${d}`; 68 | } 69 | 70 | export function getOffsetTop(relativeNode, node, topSum = 0) { 71 | topSum += node.offsetTop; 72 | 73 | if (node.offsetParent !== relativeNode) { 74 | return getOffsetTop(relativeNode, node.offsetParent, topSum); 75 | } 76 | return topSum; 77 | } 78 | 79 | export function pick(obj = {}, keys = []) { 80 | const result = {}; 81 | keys.forEach((key) => { 82 | if (obj.hasOwnProperty(key)) { 83 | result[key] = obj[key]; 84 | } 85 | }); 86 | return result; 87 | } 88 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import {createApp} from 'vue' 2 | import App from './App.vue' 3 | import "./assets/style/reset.css"; 4 | import "./assets/style/global.css"; 5 | import router from './router' 6 | import store from "./store"; 7 | import * as ElementPlusIconsVue from '@element-plus/icons-vue' 8 | import api from './api/api.js' 9 | 10 | 11 | import Loading from "./components/Loading/index.js"; 12 | 13 | const app = createApp(App) 14 | app.use(router).use(store) 15 | app.use(Loading) 16 | app.config.globalProperties.$api = api 17 | 18 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) { 19 | app.component(key, component) 20 | } 21 | 22 | app.mount('#app') 23 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import {createRouter, createWebHashHistory} from "vue-router"; 2 | 3 | const routes = [ 4 | { 5 | path: '/', 6 | name: 'home', 7 | component: () => import('../views/Home/Home.vue') 8 | }, 9 | { 10 | path: '/jobs', 11 | name: 'jobs', 12 | component: () => import('../views/Jobs/Jobs.vue') 13 | }, 14 | { 15 | path: '/jobs/:id', 16 | name: 'jobDetail', 17 | component: () => import('../views/JobDetail/JobDetail.vue') 18 | }, 19 | { 20 | path: '/staff-stories/:id', 21 | name: 'staff-stories', 22 | component: () => import('../views/StaffStories/StaffStories.vue') 23 | }, 24 | { 25 | path: '/products', 26 | name: 'products', 27 | component: () => import('../views/Products/Products.vue') 28 | }, 29 | { 30 | path: '/user', 31 | name: 'user', 32 | component: () => import('../views/User/User.vue') 33 | }, 34 | { 35 | path: '/login', 36 | name: 'login', 37 | component: () => import('../views/Login/Login.vue') 38 | }, 39 | { 40 | path: '/test', 41 | name: 'test', 42 | component: () => import('../views/Test/index.vue') 43 | } 44 | ] 45 | 46 | const router = createRouter({ 47 | history: createWebHashHistory(), 48 | routes 49 | }) 50 | 51 | export default router 52 | 53 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import {createStore} from "vuex"; 2 | 3 | export default createStore({ 4 | state: { 5 | userid: localStorage.getItem('userid') || '', 6 | username: localStorage.getItem('username') || '', 7 | token: localStorage.getItem('token') || '', 8 | role: localStorage.getItem('role') || '', 9 | }, 10 | 11 | mutations: { 12 | LOGIN(state, {userid, username, token, role}) { 13 | state.userid = userid 14 | state.username = username 15 | state.token = token 16 | state.role = role 17 | 18 | localStorage.setItem('userid', userid) 19 | localStorage.setItem('username', username) 20 | localStorage.setItem('token', token) 21 | localStorage.setItem('role', role) 22 | }, 23 | 24 | LOGOUT(state, context) { 25 | state.userid = '' 26 | state.username = '' 27 | state.token = '' 28 | state.role = '' 29 | localStorage.removeItem('userid') 30 | localStorage.removeItem('username') 31 | localStorage.removeItem('token') 32 | localStorage.removeItem('role') 33 | } 34 | }, 35 | 36 | getters: { 37 | 38 | } 39 | }) -------------------------------------------------------------------------------- /src/test/test.js: -------------------------------------------------------------------------------- 1 | // function add(n) { 2 | // 3 | // function temp(b=0) { 4 | // n = n + b 5 | // if (b) { 6 | // return temp 7 | // } else { 8 | // return n 9 | // } 10 | // } 11 | // 12 | // return temp 13 | // } 14 | // 15 | // console.log(add(1)(2)(3)()) 16 | 17 | // var sum = 0 18 | // function add(x) { 19 | // 20 | // if (x) { 21 | // sum += x 22 | // return add 23 | // 24 | // } else { 25 | // return sum 26 | // } 27 | // } 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/views/Home/Home.vue: -------------------------------------------------------------------------------- 1 | 185 | 186 | 312 | 313 | -------------------------------------------------------------------------------- /src/views/JobDetail/JobDetail.vue: -------------------------------------------------------------------------------- 1 | 24 | 67 | 105 | -------------------------------------------------------------------------------- /src/views/Jobs/Jobs.vue: -------------------------------------------------------------------------------- 1 | 76 | 77 | 201 | 202 | -------------------------------------------------------------------------------- /src/views/Login/Login.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 120 | 121 | -------------------------------------------------------------------------------- /src/views/Products/Products.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 120 | 121 | -------------------------------------------------------------------------------- /src/views/StaffStories/StaffStories.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 59 | 60 | -------------------------------------------------------------------------------- /src/views/Test/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 25 | 26 | -------------------------------------------------------------------------------- /src/views/User/User.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import AutoImport from 'unplugin-auto-import/vite' 4 | import Components from 'unplugin-vue-components/vite' 5 | import {ElementPlusResolver} from 'unplugin-vue-components/resolvers' 6 | import path from "path"; 7 | 8 | // https://vitejs.dev/config/ 9 | export default defineConfig({ 10 | plugins: [ 11 | vue(), 12 | AutoImport({ 13 | resolvers: [ElementPlusResolver()], 14 | }), 15 | Components({ 16 | resolvers: [ElementPlusResolver()], 17 | }), 18 | ], 19 | 20 | css: { 21 | preprocessorOptions: { 22 | less: { 23 | additionalData: `@import "${path.resolve(__dirname, 'src/assets/style/variable.less')}";`, 24 | javascriptEnabled: true, 25 | } 26 | }, 27 | }, 28 | 29 | }) 30 | --------------------------------------------------------------------------------