diff --git a/jvue-admin/vue.config.js b/jvue-admin/vue.config.js new file mode 100644 index 0000000..48fa9ec --- /dev/null +++ b/jvue-admin/vue.config.js @@ -0,0 +1,7 @@ +module.exports = { + // https://cli.vuejs.org/zh/config/#configurewebpack + configureWebpack: config => { + // 解决Invalid Host header + config.devServer.set('disableHostCheck', true); + } +} \ No newline at end of file diff --git a/jvue-front/.env b/jvue-front/.env new file mode 100644 index 0000000..76f4e40 --- /dev/null +++ b/jvue-front/.env @@ -0,0 +1,9 @@ +# 全局环境变量 +# 应用根路径 +VUE_APP_PUBLIC_PATH=/ +# 后台管理根路径 +VUE_APP_ADMIN_PATH=/a +# 是否允许打印debug日志 +VUE_APP_DEBUG=true +VUE_APP_INFO=true +VUE_APP_ERROR=true \ No newline at end of file diff --git a/jvue-front/.env.development b/jvue-front/.env.development new file mode 100644 index 0000000..ad694df --- /dev/null +++ b/jvue-front/.env.development @@ -0,0 +1 @@ +# 开发环境环境变量 \ No newline at end of file diff --git a/jvue-front/.env.production b/jvue-front/.env.production new file mode 100644 index 0000000..ce50e15 --- /dev/null +++ b/jvue-front/.env.production @@ -0,0 +1 @@ +# 生产环境环境变量 \ No newline at end of file diff --git a/jvue-front/.env.test b/jvue-front/.env.test new file mode 100644 index 0000000..c1c08c7 --- /dev/null +++ b/jvue-front/.env.test @@ -0,0 +1 @@ +# 测试环境环境变量 \ No newline at end of file diff --git a/jvue-front/.eslintignore b/jvue-front/.eslintignore new file mode 100644 index 0000000..0baf809 --- /dev/null +++ b/jvue-front/.eslintignore @@ -0,0 +1 @@ +*.min.js \ No newline at end of file diff --git a/jvue-front/.eslintrc.js b/jvue-front/.eslintrc.js index 3f3df4f..92a6088 100644 --- a/jvue-front/.eslintrc.js +++ b/jvue-front/.eslintrc.js @@ -5,8 +5,17 @@ module.exports = { }, extends: ["plugin:vue/essential", "@vue/prettier"], rules: { - "no-console": process.env.NODE_ENV === "production" ? "error" : "off", - "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" + "no-undef": "off", + "no-console": "off", //process.env.NODE_ENV === "production" ? "error" : "off", + "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", + "no-unused-vars": [ + 2, + { + vars: "local", + args: "none" + } + ], + semi: ["error", "always"] }, parserOptions: { parser: "babel-eslint" diff --git a/jvue-front/.gitignore b/jvue-front/.gitignore index 912d2e7..c3bd1b8 100644 --- a/jvue-front/.gitignore +++ b/jvue-front/.gitignore @@ -2,17 +2,12 @@ node_modules /dist -/tests/e2e/reports/ -selenium-debug.log - # local env files .env.local .env.*.local # Log files npm-debug.log* -yarn-debug.log* -yarn-error.log* # Editor directories and files .idea diff --git a/jvue-front/Dockerfile b/jvue-front/Dockerfile deleted file mode 100644 index b087224..0000000 --- a/jvue-front/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -#依赖的镜像 -FROM node:10.15.1-alpine - -# CDN注册 -RUN npm config set registry https://registry.npm.taobao.org && \ - npm set chromedriver_cdnurl https://npm.taobao.org/mirrors/chromedriver && \ - npm cache clean --force - -# 工作目录 -WORKDIR /app - -# 安装依赖 -COPY ./jvue-front/package.json ./ -RUN npm install - -# 注意这个一定要要在npm install后面,否则devDependencies的包无法安装 -ENV HOST 0.0.0.0 - -COPY ./jvue-front . - -CMD ["npm", "run", "serve"] \ No newline at end of file diff --git a/jvue-front/README.md b/jvue-front/README.md deleted file mode 100644 index 041cb4c..0000000 --- a/jvue-front/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# jvue-front - -## Project setup -``` -yarn install -``` - -### Compiles and hot-reloads for development -``` -yarn run serve -``` - -### Compiles and minifies for production -``` -yarn run build -``` - -### Run your tests -``` -yarn run test -``` - -### Lints and fixes files -``` -yarn run lint -``` - -### Run your end-to-end tests -``` -yarn run test:e2e -``` - -### Run your unit tests -``` -yarn run test:unit -``` - -### Customize configuration -See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/jvue-front/build/build.dev.cmd b/jvue-front/build/build.dev.cmd new file mode 100644 index 0000000..6577ea0 --- /dev/null +++ b/jvue-front/build/build.dev.cmd @@ -0,0 +1,5 @@ +npm run clean &&^ +npm run dev-build &&^ +move %cd%\dist\index.html %cd%\dist\index.ssr.html &&^ +%cd%\build\cpm.cmd &&^ +echo "build for development success." \ No newline at end of file diff --git a/jvue-front/build/build.dev.sh b/jvue-front/build/build.dev.sh new file mode 100644 index 0000000..49a41fb --- /dev/null +++ b/jvue-front/build/build.dev.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +pwd +npm run clean +npm run dev-build +mv dist/index.html dist/index.ssr.html +build/cpm.sh +echo "build for development success." \ No newline at end of file diff --git a/jvue-front/build/build.prod.cmd b/jvue-front/build/build.prod.cmd new file mode 100644 index 0000000..ef458a8 --- /dev/null +++ b/jvue-front/build/build.prod.cmd @@ -0,0 +1,5 @@ +npm run clean &&^ +npm run build &&^ +move %cd%\dist\index.html %cd%\dist\index.ssr.html &&^ +%cd%\build\cpm.cmd &&^ +echo "build for production success." \ No newline at end of file diff --git a/jvue-front/build/build.prod.sh b/jvue-front/build/build.prod.sh new file mode 100644 index 0000000..603e12f --- /dev/null +++ b/jvue-front/build/build.prod.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +npm run clean +npm run build +mv dist/index.html dist/index.ssr.html +build/cpm.sh +echo "build for production success." \ No newline at end of file diff --git a/jvue-front/build/cpm.cmd b/jvue-front/build/cpm.cmd new file mode 100644 index 0000000..26ae42c --- /dev/null +++ b/jvue-front/build/cpm.cmd @@ -0,0 +1,58 @@ +REM %cd%\build\cpm.cmd +REM ncp [source] [dest] [--limit=concurrency limit] [--filter=filter] --stopOnErr + +REM clean && mkdir +del "dist/node_modules" /q +mkdir "dist/node_modules" + +REM core-js +node node_modules/ncp/bin/ncp node_modules/core-js dist/node_modules/core-js + +REM vue-server-renderer +node node_modules/ncp/bin/ncp node_modules/he dist/node_modules/he +node node_modules/ncp/bin/ncp node_modules/lodash._reinterpolate dist/node_modules/lodash._reinterpolate +node node_modules/ncp/bin/ncp node_modules/lodash.template dist/node_modules/lodash.template +node node_modules/ncp/bin/ncp node_modules/lodash.templatesettings dist/node_modules/lodash.templatesettings +node node_modules/ncp/bin/ncp node_modules/resolve dist/node_modules/resolve +node node_modules/ncp/bin/ncp node_modules/serialize-javascript dist/node_modules/serialize-javascript +node node_modules/ncp/bin/ncp node_modules/vue-server-renderer dist/node_modules/vue-server-renderer +del dist/node_modules/vue-server-renderer/node_modules /q + +REM vue +node node_modules/ncp/bin/ncp node_modules/vue dist/node_modules/vue + +REM vue-router +node node_modules/ncp/bin/ncp node_modules/vue-router dist/node_modules/vue-router + +REM axios +node node_modules/ncp/bin/ncp node_modules/axios dist/node_modules/axios +node node_modules/ncp/bin/ncp node_modules/is-buffer dist/node_modules/is-buffer +node node_modules/ncp/bin/ncp node_modules/follow-redirects dist/node_modules/follow-redirects + +REM bootstrap-vue +node node_modules/ncp/bin/ncp node_modules/bootstrap-vue dist/node_modules/bootstrap-vue +del "dist/node_modules/bootstrap-vue/node_modules" /q +del "dist/node_modules/bootstrap-vue/src" /q + +REM circular-json +node node_modules/ncp/bin/ncp node_modules/circular-json dist/node_modules/circular-json + +REM source-map +node node_modules/ncp/bin/ncp node_modules/source-map dist/node_modules/source-map + +REM url-search-params-polyfill +node node_modules/ncp/bin/ncp node_modules/url-search-params-polyfill dist/node_modules/url-search-params-polyfill + +REM vue-hljs +node node_modules/ncp/bin/ncp node_modules/vue-hljs dist/node_modules/vue-hljs +node node_modules/ncp/bin/ncp node_modules/highlight.js dist/node_modules/highlight.js + +REM element-ui +node node_modules/ncp/bin/ncp node_modules/element-ui dist/node_modules/element-ui +node node_modules/ncp/bin/ncp node_modules/deepmerge dist/node_modules/deepmerge +node node_modules/ncp/bin/ncp node_modules/resize-observer-polyfill dist/node_modules/resize-observer-polyfill +node node_modules/ncp/bin/ncp node_modules/throttle-debounce dist/node_modules/throttle-debounce +node node_modules/ncp/bin/ncp node_modules/normalize-wheel dist/node_modules/normalize-wheel +node node_modules/ncp/bin/ncp node_modules/async-validator dist/node_modules/async-validator +node node_modules/ncp/bin/ncp node_modules/babel-runtime dist/node_modules/babel-runtime +node node_modules/ncp/bin/ncp node_modules/babel-helper-vue-jsx-merge-props dist/node_modules/babel-helper-vue-jsx-merge-props \ No newline at end of file diff --git a/jvue-front/build/cpm.sh b/jvue-front/build/cpm.sh new file mode 100644 index 0000000..0528197 --- /dev/null +++ b/jvue-front/build/cpm.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# dos2unix ./build/cpm.sh && ./build/cpm.sh +# node_modules/ncp/bin/ncp [source] [dest] [--limit=concurrency limit] [--filter=filter] --stopOnErr + +# clean & mkdir +rm -rf dist/node_modules +mkdir -p dist/node_modules + +# core-js +node_modules/ncp/bin/ncp node_modules/core-js dist/node_modules/core-js + +# vue-server-renderer +node_modules/ncp/bin/ncp node_modules/he dist/node_modules/he +node_modules/ncp/bin/ncp node_modules/lodash._reinterpolate dist/node_modules/lodash._reinterpolate +node_modules/ncp/bin/ncp node_modules/lodash.template dist/node_modules/lodash.template +node_modules/ncp/bin/ncp node_modules/lodash.templatesettings dist/node_modules/lodash.templatesettings +node_modules/ncp/bin/ncp node_modules/resolve dist/node_modules/resolve +node_modules/ncp/bin/ncp node_modules/serialize-javascript dist/node_modules/serialize-javascript +node_modules/ncp/bin/ncp node_modules/vue-server-renderer dist/node_modules/vue-server-renderer +rm -rf dist/node_modules/vue-server-renderer/node_modules + +# vue +node_modules/ncp/bin/ncp node_modules/vue dist/node_modules/vue + +# vue-router +node_modules/ncp/bin/ncp node_modules/vue-router dist/node_modules/vue-router + +# axios +node_modules/ncp/bin/ncp node_modules/axios dist/node_modules/axios +node_modules/ncp/bin/ncp node_modules/is-buffer dist/node_modules/is-buffer +node_modules/ncp/bin/ncp node_modules/follow-redirects dist/node_modules/follow-redirects + +# bootstrap-vue +node_modules/ncp/bin/ncp node_modules/bootstrap-vue dist/node_modules/bootstrap-vue +rm -rf dist/node_modules/bootstrap-vue/node_modules +rm -rf dist/node_modules/bootstrap-vue/src + +# circular-json +node_modules/ncp/bin/ncp node_modules/circular-json dist/node_modules/circular-json + +# source-map +node_modules/ncp/bin/ncp node_modules/source-map dist/node_modules/source-map + +# url-search-params-polyfill +node_modules/ncp/bin/ncp node_modules/url-search-params-polyfill dist/node_modules/url-search-params-polyfill + +# vue-hljs +node_modules/ncp/bin/ncp node_modules/vue-hljs dist/node_modules/vue-hljs +node_modules/ncp/bin/ncp node_modules/highlight.js dist/node_modules/highlight.js + +# element-ui +node_modules/ncp/bin/ncp node_modules/element-ui dist/node_modules/element-ui +node_modules/ncp/bin/ncp node_modules/deepmerge dist/node_modules/deepmerge +node_modules/ncp/bin/ncp node_modules/resize-observer-polyfill dist/node_modules/resize-observer-polyfill +node_modules/ncp/bin/ncp node_modules/throttle-debounce dist/node_modules/throttle-debounce +node_modules/ncp/bin/ncp node_modules/normalize-wheel dist/node_modules/normalize-wheel +node_modules/ncp/bin/ncp node_modules/async-validator dist/node_modules/async-validator +node_modules/ncp/bin/ncp node_modules/babel-runtime dist/node_modules/babel-runtime +node_modules/ncp/bin/ncp node_modules/babel-helper-vue-jsx-merge-props dist/node_modules/babel-helper-vue-jsx-merge-props \ No newline at end of file diff --git a/jvue-front/jest.config.js b/jvue-front/jest.config.js deleted file mode 100644 index 8b0e1e5..0000000 --- a/jvue-front/jest.config.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - moduleFileExtensions: ["js", "jsx", "json", "vue"], - transform: { - "^.+\\.vue$": "vue-jest", - ".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$": - "jest-transform-stub", - "^.+\\.jsx?$": "babel-jest" - }, - transformIgnorePatterns: ["/node_modules/"], - moduleNameMapper: { - "^@/(.*)$": "/src/$1" - }, - snapshotSerializers: ["jest-serializer-vue"], - testMatch: [ - "**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)" - ], - testURL: "http://localhost/" -}; diff --git a/jvue-front/package.json b/jvue-front/package.json index 3de0bee..3ff301b 100644 --- a/jvue-front/package.json +++ b/jvue-front/package.json @@ -1,35 +1,76 @@ { - "name": "jvue-front", - "version": "0.1.0", + "name": "jvue", + "version": "3.0.0", "private": true, "scripts": { - "serve": "vue-cli-service serve --port 3000", - "dev": "vue-cli-service serve --port 3000 --mode production", - "start": "npm run build && npm run dev", - "build": "vue-cli-service build", + "clean": "rimraf dist", "lint": "vue-cli-service lint", - "test:e2e": "vue-cli-service test:e2e", - "test:unit": "vue-cli-service test:unit" + "serve": "cross-env NODE_ENV=development vue-cli-service serve", + "dev-build-entry-client": "cross-env SSR_ENV=client vue-cli-service build --mode development", + "build-entry-client": "cross-env SSR_ENV=client vue-cli-service build", + "dev-build-entry-server": "cross-env SSR_ENV=server vue-cli-service build --mode development --no-clean", + "build-entry-server": "cross-env SSR_ENV=server vue-cli-service build --no-clean", + "dev-build": "npm run dev-build-entry-client && npm run dev-build-entry-server && node node_modules/@babel/cli/bin/babel --presets=@babel/preset-env -o dist/server.js src/server.js", + "build": "npm run build-entry-client && npm run build-entry-server && node node_modules/@babel/cli/bin/babel -o dist/server.js --presets=@babel/preset-env,minify src/server.js", + "build-nossr": "npm run build-entry-client", + "dev-build-nossr": "npm run dev-build-entry-client", + "dev-start": "cross-env NODE_ENV=development node tests/dev-server.js", + "prod-start": "cross-env NODE_ENV=production node tests/dev-server.js", + "v8-dev-start": "cross-env NODE_ENV=development node tests/v8-server.js", + "v8-prod-start": "cross-env NODE_ENV=production node tests/v8-server.js" }, "dependencies": { - "vue": "^2.6.6", - "vue-router": "^3.0.1" + "axios": "^0.18.0", + "bootstrap": "latest", + "bootstrap-vue": "^2.0.0-rc.13", + "circular-json": "^0.5.9", + "element-ui": "^2.6.1", + "font-awesome": "^4.7.0", + "url-search-params-polyfill": "^5.0.0", + "v-toaster": "^1.0.3", + "vue": "^2.6.7", + "vue-hljs": "^1.1.2", + "vue-progressbar": "^0.7.5", + "vue-router": "^3.0.2", + "vue-server-renderer": "^2.6.7", + "vue-uweb": "^0.2.1", + "vue-web-storage": "^4.0.0" }, "devDependencies": { - "@vue/cli-plugin-babel": "^3.5.0", - "@vue/cli-plugin-e2e-nightwatch": "^3.5.0", - "@vue/cli-plugin-eslint": "^3.5.0", - "@vue/cli-plugin-unit-jest": "^3.5.0", - "@vue/cli-service": "^3.5.0", + "@babel/cli": "^7.2.3", + "@babel/core": "^7.3.4", + "@vue/cli-plugin-babel": "^3.4.0", + "@vue/cli-plugin-eslint": "^3.4.0", + "@vue/cli-service": "^3.4.0", "@vue/eslint-config-prettier": "^4.0.1", - "@vue/test-utils": "1.0.0-beta.29", "babel-core": "7.0.0-bridge.0", "babel-eslint": "^10.0.1", - "babel-jest": "^23.6.0", + "babel-minify": "^0.5.0", + "babel-preset-minify": "^0.5.0", + "cross-env": "^5.2.0", "eslint": "^5.8.0", "eslint-plugin-vue": "^5.0.0", + "express": "^4.16.4", + "lint-staged": "^8.1.0", + "ncp": "^2.0.0", "node-sass": "^4.9.0", - "sass-loader": "^7.1.0", - "vue-template-compiler": "^2.5.21" + "rimraf": "^2.6.3", + "sass-loader": "7.1.0", + "vue-template-compiler": "^2.5.21", + "webpack": "^4.29.5", + "webpack-node-externals": "^1.7.2" + }, + "gitHooks": { + "pre-commit": "lint-staged" + }, + "lint-staged": { + "*.js": [ + "vue-cli-service lint", + "git add" + ], + "*.vue": [ + "vue-cli-service lint", + "git add" + ] } } diff --git a/jvue-front/public/favicon.ico b/jvue-front/public/favicon.ico index c7b9a43..a76ddd3 100644 Binary files a/jvue-front/public/favicon.ico and b/jvue-front/public/favicon.ico differ diff --git a/jvue-front/public/index.html b/jvue-front/public/index.html index 1da71e2..345a972 100644 --- a/jvue-front/public/index.html +++ b/jvue-front/public/index.html @@ -1,17 +1,42 @@ + - - - - - - - jvue-front - - - -
- - - + + + + + + <% if(htmlWebpackPlugin.options.ssrEnv=="client"){ %> + 这里是Java展示的标题 + <% }else{ %> + <%= htmlWebpackPlugin.options.title %> + <% } %> + + + + + + +<% if(htmlWebpackPlugin.options.ssrEnv=="client"){ %> + + +<% }else{ %> + +<% } %> +
+ +

ssrEnv=><%= htmlWebpackPlugin.options.ssrEnv %>

+

debug=><%= htmlWebpackPlugin.options.debug %>

+ + \ No newline at end of file diff --git a/jvue-front/src/App.vue b/jvue-front/src/App.vue index 440354e..525c670 100644 --- a/jvue-front/src/App.vue +++ b/jvue-front/src/App.vue @@ -1,19 +1,37 @@ + + diff --git a/jvue-front/src/components/admin/Header.vue b/jvue-front/src/components/admin/Header.vue new file mode 100644 index 0000000..1b75734 --- /dev/null +++ b/jvue-front/src/components/admin/Header.vue @@ -0,0 +1,225 @@ + + + diff --git a/jvue-front/src/components/admin/Sidebar.vue b/jvue-front/src/components/admin/Sidebar.vue new file mode 100644 index 0000000..622de32 --- /dev/null +++ b/jvue-front/src/components/admin/Sidebar.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/jvue-front/src/components/admin/Tags.vue b/jvue-front/src/components/admin/Tags.vue new file mode 100644 index 0000000..d7f36ba --- /dev/null +++ b/jvue-front/src/components/admin/Tags.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/jvue-front/src/components/admin/bus.js b/jvue-front/src/components/admin/bus.js new file mode 100644 index 0000000..514be67 --- /dev/null +++ b/jvue-front/src/components/admin/bus.js @@ -0,0 +1,13 @@ +/** + * bus + * + *@author Terwer + *@version 1.0 + *2019/3/4 14:49 + **/ +import Vue from "vue"; + +// 使用 Event Bus +const bus = new Vue(); + +export default bus; diff --git a/jvue-front/src/components/themes/default/Aside.vue b/jvue-front/src/components/themes/default/Aside.vue new file mode 100644 index 0000000..bac883f --- /dev/null +++ b/jvue-front/src/components/themes/default/Aside.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/jvue-front/src/components/themes/default/Body.vue b/jvue-front/src/components/themes/default/Body.vue new file mode 100644 index 0000000..4b4061a --- /dev/null +++ b/jvue-front/src/components/themes/default/Body.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/jvue-front/src/components/themes/default/Footer.vue b/jvue-front/src/components/themes/default/Footer.vue new file mode 100644 index 0000000..20ff048 --- /dev/null +++ b/jvue-front/src/components/themes/default/Footer.vue @@ -0,0 +1,234 @@ + + + + + diff --git a/jvue-front/src/components/themes/default/FriendLink.vue b/jvue-front/src/components/themes/default/FriendLink.vue new file mode 100644 index 0000000..c9910ee --- /dev/null +++ b/jvue-front/src/components/themes/default/FriendLink.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/jvue-front/src/components/themes/default/Header.vue b/jvue-front/src/components/themes/default/Header.vue new file mode 100644 index 0000000..4b9e4b9 --- /dev/null +++ b/jvue-front/src/components/themes/default/Header.vue @@ -0,0 +1,225 @@ + + + diff --git a/jvue-front/src/components/themes/default/HeaderMenu.vue b/jvue-front/src/components/themes/default/HeaderMenu.vue new file mode 100644 index 0000000..388a91b --- /dev/null +++ b/jvue-front/src/components/themes/default/HeaderMenu.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/jvue-front/src/components/themes/default/HeaderTime.vue b/jvue-front/src/components/themes/default/HeaderTime.vue new file mode 100644 index 0000000..d451592 --- /dev/null +++ b/jvue-front/src/components/themes/default/HeaderTime.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/jvue-front/src/components/themes/default/PostList.vue b/jvue-front/src/components/themes/default/PostList.vue new file mode 100644 index 0000000..9bbae67 --- /dev/null +++ b/jvue-front/src/components/themes/default/PostList.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/jvue-front/src/components/themes/default/style.css b/jvue-front/src/components/themes/default/style.css new file mode 100644 index 0000000..89a341e --- /dev/null +++ b/jvue-front/src/components/themes/default/style.css @@ -0,0 +1,33 @@ +/*! + * Theme Name: terwer + * Theme URL: http://www.terwergreen.com + * Description: 本主题是一款适合博客、新闻资讯、自媒体的主题模板。基于bootstrap响应式布局,自适应PC、手机、平板等多种设备浏览。包含普通文章、专题、视频、图集、下载五中文章类型,多种文章页模板。自带前端用户中心,前端登录注册、资料编辑、投稿、文章编辑、评论管理、收藏管理、用户关注一应俱全。文章列表及评论列表AJAX加载。视频支持本地上传、视频链接及视频平台视频。 + * Author: 倚楼听雨 + * Author URI: http://www.terwergreen.com + * Tags:blog + * Version: 1.0 + */ +body { + font-family: "Microsoft Yahei", Helvetica, Arial, Verdana, Tahoma, sans-serif !important; + color: #666 !important; +} +body, +* { + box-sizing: border-box; +} +ul { + list-style: none; +} +.hide { + display: none; +} + +/*! + * 遮罩层 + */ +.mask { + position:fixed; + top: 0;right: 0;left: 0;bottom: 0; + background:rgba(0,0,0,0.6); + z-index: 999999; +} \ No newline at end of file diff --git a/jvue-front/src/entry-client.js b/jvue-front/src/entry-client.js new file mode 100644 index 0000000..5d2d818 --- /dev/null +++ b/jvue-front/src/entry-client.js @@ -0,0 +1,104 @@ +/** + * 仅运行于浏览器 + * + *@author Terwer + *@version 1.0 + *2019/2/27 10:00 + **/ +import { getLogger } from "./util/logger"; +const logger = getLogger("entry-client"); +import { getSession } from "./util/storage"; +import { createApp } from "./app"; + +// CSS只在客户端引用 +// import "bootstrap/dist/css/bootstrap.css"; +// import "bootstrap-vue/dist/bootstrap-vue.css"; +// import "v-toaster/dist/v-toaster.css"; + +// 公共样式库 +import(/* webpackChunkName: "bootstrap-style" */ "bootstrap/dist/css/bootstrap.css"); +import(/* webpackChunkName: "bootstrap-vue-style" */ "bootstrap-vue/dist/bootstrap-vue.css"); +import(/* webpackChunkName: "v-toaster-style" */ "v-toaster/dist/v-toaster.css"); +// import(/* webpackChunkName: "vue-hljs-style" */ "vue-hljs/dist/vue-hljs.min.css"); +import(/* webpackChunkName: "vue-hljs-style" */ "./lib/vue-hljs/vs.css"); + +// 自定义样式库 +// import "components/themes/default/style.css"; +import(/* webpackChunkName: "jvue-style" */ "./components/themes/default/style.css"); + +// 后台管理地址 +const ADMIN_PATH = process.env.VUE_APP_ADMIN_PATH; + +// 客户端特定引导逻辑…… +createApp().then(resolve => { + const app = resolve.app; + const router = resolve.router; + + // wait until router has resolved all async before hooks + // and async components... + router.onReady(() => { + // Add router hook for handling asyncData. + // Doing it after initial route is resolved so that we don't double-fetch + // the data that we already have. Using router.beforeResolve() so that all + // async components are resolved. + router.beforeResolve((to, from, next) => { + app.$Progress.start(); + + logger.info("to=>"); + console.log(to); + logger.info("from=>"); + console.log(from); + + const matched = router.getMatchedComponents(to); + const prevMatched = router.getMatchedComponents(from); + logger.info("matched=>", matched); + logger.info("prevMatched=>", prevMatched); + let diffed = false; + + //使用钩子函数对路由进行权限跳转 + const role = getSession("ms_username"); + console.log("role=>", role); + const adminLoginPath = ADMIN_PATH + "/login"; + if (!role && to.path !== adminLoginPath) { + return next(adminLoginPath); + } + + // 查找当前活动的组件 + const activated = matched.filter((component, i) => { + return diffed || (diffed = prevMatched[i] !== component); + }); + if (!activated.length) { + app.$Progress.finish(); + return next(); + } + + // 对所有匹配的路由组件调用 `asyncData()` + Promise.all( + activated.map(Component => { + if (Component.asyncData) { + logger.info("调用asyncData获取数据"); + return Component.asyncData({ + from: from, + to: to + }); + } else { + logger.info("未找到asyncData"); + } + }) + ) + .then(res => { + app.$Progress.finish(); + // 这里的结果会保存在SessionStorage + logger.debug("matchedComponents asyncData res=>", res); + next(); + }) + .catch(rejected => { + app.$toaster.error(rejected); + next(); + }); + }); + }); + + // 这里假定 App.vue 模板中根元素具有 `id="app"` + app.$mount("#app"); +}); diff --git a/jvue-front/src/entry-server.js b/jvue-front/src/entry-server.js new file mode 100644 index 0000000..32ca737 --- /dev/null +++ b/jvue-front/src/entry-server.js @@ -0,0 +1,66 @@ +/** + * 仅运行于服务器 + * + *@author Terwer + *@version 1.0 + *2019/2/27 10:00 + **/ +import { getLogger } from "./util/logger"; +const logger = getLogger("entry-server"); +import { createApp } from "./app"; + +export default context => { + // 因为有可能会是异步路由钩子函数或组件,所以我们将返回一个 Promise, + // 以便服务器能够等待所有的内容在渲染前, + // 就已经准备就绪。 + return new Promise((resolve, reject) => { + createApp().then(resolveInstance => { + const app = resolveInstance.app; + const router = resolveInstance.router; + + // 设置服务器端 router 的位置 + router.push(context.url); + + // 等到 router 将可能的异步组件和钩子函数解析完 + router.onReady(() => { + const matchedComponents = router.getMatchedComponents(); + // 匹配不到的路由,执行 reject 函数,并返回 404 + if (!matchedComponents.length) { + return reject({ code: 404 }); + } + + // 对所有匹配的路由组件调用 `asyncData()` + Promise.all( + matchedComponents.map(Component => { + if (Component.asyncData) { + logger.info("调用asyncData获取数据"); + return Component.asyncData({ + to: router.currentRoute + }); + } + }) + ) + .then(res => { + // 在所有预取钩子(preFetch hook) resolve 后, + // 我们的 store 现在已经填充入渲染应用程序所需的状态。 + // 当我们将状态附加到上下文, + // 并且 `template` 选项用于 renderer 时, + // 状态将自动序列化为 `window.__INITIAL_STATE__`,并注入 HTML。 + // console.log("matchedComponents asyncData res=>", res); + logger.info( + "matchedComponents asyncData set res to window.__INITIAL_STATE__" + ); + logger.debug(res); + context.state = res; + + // Promise 应该 resolve 应用程序实例,以便它可以渲染 + resolve(app); + }) + .catch(rejected => { + logger.error("asyncData rejected=>"); + console.error(rejected); + }); + }, reject); + }); + }); +}; diff --git a/jvue-front/src/lib/vue-hljs/vs.css b/jvue-front/src/lib/vue-hljs/vs.css new file mode 100644 index 0000000..84b31c5 --- /dev/null +++ b/jvue-front/src/lib/vue-hljs/vs.css @@ -0,0 +1,45 @@ +.hljs { + display: block; + overflow-x: auto; + padding: .5em; + color: black; + background-color: #f5f5f5!important; + border: 1px solid #ccc!important; + border-radius: 3px!important; +} + +.hljs-comment, .hljs-quote, .hljs-variable { + color: #008000 +} + +.hljs-keyword, .hljs-selector-tag, .hljs-built_in, .hljs-name, .hljs-tag { + color: #00f +} + +.hljs-string, .hljs-title, .hljs-section, .hljs-attribute, .hljs-literal, .hljs-template-tag, .hljs-template-variable, .hljs-type, .hljs-addition { + color: #a31515 +} + +.hljs-deletion, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-meta { + color: #2b91af +} + +.hljs-doctag { + color: #808080 +} + +.hljs-attr { + color: #f00 +} + +.hljs-symbol, .hljs-bullet, .hljs-link { + color: #00b0e8 +} + +.hljs-emphasis { + font-style: italic +} + +.hljs-strong { + font-weight: bold +} \ No newline at end of file diff --git a/jvue-front/src/lib/vue-hljs/vs2015.css b/jvue-front/src/lib/vue-hljs/vs2015.css new file mode 100644 index 0000000..584d7e0 --- /dev/null +++ b/jvue-front/src/lib/vue-hljs/vs2015.css @@ -0,0 +1,85 @@ +.hljs { + display: block; + overflow-x: auto; + padding: .5em; + background: #1E1E1E; + color: #DCDCDC +} + +.hljs-keyword, .hljs-literal, .hljs-symbol, .hljs-name { + color: #569CD6 +} + +.hljs-link { + color: #569CD6; + text-decoration: underline +} + +.hljs-built_in, .hljs-type { + color: #4EC9B0 +} + +.hljs-number, .hljs-class { + color: #B8D7A3 +} + +.hljs-string, .hljs-meta-string { + color: #D69D85 +} + +.hljs-regexp, .hljs-template-tag { + color: #9A5334 +} + +.hljs-subst, .hljs-function, .hljs-title, .hljs-params, .hljs-formula { + color: #DCDCDC +} + +.hljs-comment, .hljs-quote { + color: #57A64A; + font-style: italic +} + +.hljs-doctag { + color: #608B4E +} + +.hljs-meta, .hljs-meta-keyword, .hljs-tag { + color: #9B9B9B +} + +.hljs-variable, .hljs-template-variable { + color: #BD63C5 +} + +.hljs-attr, .hljs-attribute, .hljs-builtin-name { + color: #9CDCFE +} + +.hljs-section { + color: gold +} + +.hljs-emphasis { + font-style: italic +} + +.hljs-strong { + font-weight: bold +} + +.hljs-bullet, .hljs-selector-tag, .hljs-selector-id, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo { + color: #D7BA7D +} + +.hljs-addition { + background-color: #144212; + display: inline-block; + width: 100% +} + +.hljs-deletion { + background-color: #600; + display: inline-block; + width: 100% +} \ No newline at end of file diff --git a/jvue-front/src/main.js b/jvue-front/src/main.js deleted file mode 100644 index 1f5f073..0000000 --- a/jvue-front/src/main.js +++ /dev/null @@ -1,10 +0,0 @@ -import Vue from "vue"; -import App from "./App.vue"; -import router from "./router"; - -Vue.config.productionTip = false; - -new Vue({ - router, - render: h => h(App) -}).$mount("#app"); diff --git a/jvue-front/src/router.js b/jvue-front/src/router.js deleted file mode 100644 index 7b4bb79..0000000 --- a/jvue-front/src/router.js +++ /dev/null @@ -1,26 +0,0 @@ -import Vue from "vue"; -import Router from "vue-router"; -import Home from "./views/Home.vue"; - -Vue.use(Router); - -export default new Router({ - mode: "history", - base: process.env.BASE_URL, - routes: [ - { - path: "/", - name: "home", - component: Home - }, - { - path: "/about", - name: "about", - // route level code-splitting - // this generates a separate chunk (about.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: () => - import(/* webpackChunkName: "about" */ "./views/About.vue") - } - ] -}); diff --git a/jvue-front/src/router/admin.js b/jvue-front/src/router/admin.js new file mode 100644 index 0000000..1366e4a --- /dev/null +++ b/jvue-front/src/router/admin.js @@ -0,0 +1,46 @@ +/** + * admin + * + *@author Terwer + *@version 1.0 + *2019/3/4 12:44 + **/ +import AdminLogin from "../views/admin/AdminLogin"; +const ADMIN_PATH = process.env.VUE_APP_ADMIN_PATH; + +export default [ + { + path: ADMIN_PATH, + redirect: ADMIN_PATH + "/dashboard" + }, + { + path: ADMIN_PATH, + component: resolve => require(["../views/admin/AdminHome.vue"], resolve), + meta: { title: "系统首页" }, + children: [ + { + path: ADMIN_PATH + "/dashboard", + component: resolve => + require(["../views/admin/Dashboard.vue"], resolve), + meta: { title: "系统首页" } + }, + { + path: ADMIN_PATH + "/post/manage/list", + component: resolve => + require(["../views/admin/postManage/PostList.vue"], resolve), + meta: { title: "文章" } + }, + { + path: ADMIN_PATH + "/post/manage/edit", + component: resolve => + require(["../views/admin/postManage/PostEdit.vue"], resolve), + meta: { title: "文章" } + } + ] + }, + { + path: ADMIN_PATH + "/login", + name: "admin/login", + component: AdminLogin + } +]; diff --git a/jvue-front/src/router/front.js b/jvue-front/src/router/front.js new file mode 100644 index 0000000..586d55e --- /dev/null +++ b/jvue-front/src/router/front.js @@ -0,0 +1,93 @@ +/** + * front + * + *@author Terwer + *@version 1.0 + *2019/3/4 12:43 + **/ +import Home from "../views/Home"; +import About from "../views/About"; +import Detail from "../views/Detail"; +import Login from "../views/Login"; +import Register from "../views/Register"; +import Category from "../views/Category"; + +export default [ + { + path: "/", + name: "home", + component: Home + // component: () => + // import(/* webpackChunkName: "homepage" */ "./views/Home.vue") + }, + { + path: "/home", + name: "home-long", + component: Home + }, + { + path: "/s", + name: "search", + component: Home + }, + { + path: "/s/:k", + name: "search", + component: Home + }, + { + path: "/about", + name: "about", + component: About + // route level code-splitting + // this generates a separate chunk (aboutpage.[hash].js) for this route + // which is lazy-loaded when the route is visited. + // component: () => + // import(/* webpackChunkName: "aboutpage" */ "./views/About.vue") + }, + { + path: "/post/:id.html", + name: "detail", + component: Detail + }, + { + path: "/post/:id", + name: "detail-no-ext", + component: Detail + }, + { + path: "/p/:id.html", + name: "detail-short", + component: Detail + }, + { + path: "/p/:id", + name: "detail-short-no-ext", + component: Detail + }, + { + path: "/auth/login", + name: "login", + component: Login + }, + { + path: "/auth/register", + name: "register", + component: Register + }, + { + path: "/category/:id", + name: "category", + component: Category + }, + { + path: "/cat/:id", + name: "category-medium", + component: Category + }, + { + path: "/c/:id", + name: "category-short", + component: Category + } +]; diff --git a/jvue-front/src/router/index.js b/jvue-front/src/router/index.js new file mode 100644 index 0000000..0ca6c1d --- /dev/null +++ b/jvue-front/src/router/index.js @@ -0,0 +1,15 @@ +import Vue from "vue"; +import Router from "vue-router"; +import FrontRoute from "./front"; +import AdminRoute from "./admin"; + +Vue.use(Router); + +const routes = FrontRoute.concat(AdminRoute); +console.log("routes=>", routes); + +export default new Router({ + mode: "history", + base: process.env.BASE_URL, + routes: routes +}); diff --git a/jvue-front/src/server.js b/jvue-front/src/server.js new file mode 100644 index 0000000..1c00f74 --- /dev/null +++ b/jvue-front/src/server.js @@ -0,0 +1,65 @@ +/** + * server.js + * npm run babel src/server.js -o dist/server.js + *@author Terwer + *@version 1.0 + *2019/2/27 12:05 + **/ +const fs = require("fs"); +const path = require("path"); +const { createBundleRenderer } = require("vue-server-renderer"); + +// In production: create server renderer using built server bundle. +// The server bundle is generated by vue-ssr-webpack-plugin. +// 路径相对于 dist 文件夹 +// noinspection JSFileReferences +const template = fs.readFileSync( + path.resolve(__dirname, "./index.ssr.html"), + "utf-8" +); + +// noinspection JSFileReferences +const serverBundle = require("./vue-ssr-server-bundle.json"); +// noinspection JSFileReferences +const clientManifest = require("./vue-ssr-client-manifest.json"); +const renderer = createBundleRenderer(serverBundle, { + runInNewContext: false, // 推荐 + template, // (可选)页面模板 + clientManifest // (可选)客户端构建 manifest +}); + +/** + * 渲染服务 + * @param context 上下文 + * @param renderServerCallback 回调 + */ +const renderServer = (context, renderServerCallback) => { + const contextObj = JSON.parse(context); + const promise = renderer.renderToString(contextObj); + if (typeof renderServerCallback === "undefined") { + return promise; + } + // 如果有callback,执行callback + console.log("callback exists,calling callback..."); + promise + .then((resolve, reject) => { + if (reject) { + renderServerCallback(reject); + return; + } + console.log("renderServer resolve=>", resolve); + // 在dom中查找body + // const dom = new JSDOM(resolve); + // const placeholder = dom.window.document.querySelector("placeholder"); + // console.log("renderServer placeholder=>", placeholder.innerHTML); + // renderServerCallback(null, placeholder.innerHTML); + renderServerCallback(null, resolve); + }) + .catch(rejected => { + renderServerCallback(rejected); + }); +}; + +module.exports = { + renderServer +}; diff --git a/jvue-front/src/use-lib.js b/jvue-front/src/use-lib.js new file mode 100644 index 0000000..0323af6 --- /dev/null +++ b/jvue-front/src/use-lib.js @@ -0,0 +1,104 @@ +/** + * use-lib.js + * + * @author Terwer + * @version 1.0 + * 19-2-28 上午12:36 + **/ +import { getLogger } from "./util/logger"; +const logger = getLogger("use-lib"); +import { inBrowser } from "./util/dom"; +import Vue from "vue"; + +// 引入通用组件 +import BootstrapVue from "bootstrap-vue"; +Vue.use(BootstrapVue); +logger.debug("Register bootstrap-vue success"); + +import vueHljs from "vue-hljs"; +Vue.use(vueHljs); +logger.debug("Register vue-hljs success"); + +import ElementUI from "element-ui"; +Vue.use(ElementUI, { + size: "small" +}); +logger.debug("Register element-ui success"); + +import "url-search-params-polyfill"; +logger.debug("Register url-search-params-polyfill success"); + +// 浏览器专用 +if (inBrowser) { + const Toaster = require("v-toaster"); + // console.log("Toaster=>", Toaster); + // 持续时间,默认10秒 + Vue.use(Toaster, { timeout: 2000 }); + logger.info("Register Toaster success"); + + // import VueProgressBar from "vue-progressbar"; + const VueProgressBar = require("vue-progressbar"); + const options = { + color: "#00a4ff", + failedColor: "#ff6b68", + thickness: "2px", + transition: { + speed: "0.2s", + opacity: "0.6s", + termination: 300 + }, + autoRevert: true, + location: "top", + inverse: false + }; + Vue.use(VueProgressBar, options); + logger.info("Register VueProgressBar success"); + + // admin需要使用的库 +} else { + // 服务端专用 +} + +/** + * 动态引用依赖库 + * @returns {Promise} + */ +export const useLib = () => { + // 引入特定组件 + return new Promise((resolve, reject) => { + // 浏览器环境专用组件 + if (inBrowser) { + // 非动态注册 + const uweb = require("vue-uweb").default; + Vue.use(uweb, { + siteId: "4445524", + // http://s11.cnzz.com/z_stat.php?id=SITEID&web_id=SITEID // 文字样式 + src: "http://s5.cnzz.com/stat.php?id=4445524&show=pic" // 图片样式 + }); + logger.debug("Register uweb success"); + + // 动态注册 + // import Storage from 'vue-web-storage' + const StoragePromise = import(/* webpackChunkName: "vue-web-storage" */ "vue-web-storage"); + + Promise.all([StoragePromise]) + .then(function(values) { + // Storage + const Storage = values[0]; + Vue.use(Storage.default, { + prefix: "jvue_", // default `app_` + drivers: ["session", "local"] // default 'local' + }); + logger.debug("Register vue-web-storage success"); + + return resolve("浏览器环境组件注册成功"); + }) + .catch(rejected => { + logger.error(`Register components rejected=>${rejected}`); + return reject(rejected); + }); + } else { + return resolve("服务端环境组件注册完成"); + } + }); +}; diff --git a/jvue-front/src/util/Calendar.js b/jvue-front/src/util/Calendar.js new file mode 100644 index 0000000..605bf7f --- /dev/null +++ b/jvue-front/src/util/Calendar.js @@ -0,0 +1,1026 @@ +/** + * Calendar.js + * + *@author Terwer + *@version 1.0 + *2019/2/28 9:47 + **/ +/** + * @1900-2100区间内的公历、农历互转 + * @charset UTF-8 + * @Author Jea杨(JJonline@JJonline.Cn) + * @Time 2014-7-21 + * @Time 2016-8-13 Fixed 2033hex、Attribution Annals + * @Time 2016-9-25 Fixed lunar LeapMonth Param Bug + * @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year + * @Version 1.0.3 + * @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0] + * @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0] + */ +var calendar = { + /** + * 农历1900-2100的润大小信息表 + * @Array Of Property + * @return Hex + */ + lunarInfo: [ + 0x04bd8, + 0x04ae0, + 0x0a570, + 0x054d5, + 0x0d260, + 0x0d950, + 0x16554, + 0x056a0, + 0x09ad0, + 0x055d2, //1900-1909 + 0x04ae0, + 0x0a5b6, + 0x0a4d0, + 0x0d250, + 0x1d255, + 0x0b540, + 0x0d6a0, + 0x0ada2, + 0x095b0, + 0x14977, //1910-1919 + 0x04970, + 0x0a4b0, + 0x0b4b5, + 0x06a50, + 0x06d40, + 0x1ab54, + 0x02b60, + 0x09570, + 0x052f2, + 0x04970, //1920-1929 + 0x06566, + 0x0d4a0, + 0x0ea50, + 0x06e95, + 0x05ad0, + 0x02b60, + 0x186e3, + 0x092e0, + 0x1c8d7, + 0x0c950, //1930-1939 + 0x0d4a0, + 0x1d8a6, + 0x0b550, + 0x056a0, + 0x1a5b4, + 0x025d0, + 0x092d0, + 0x0d2b2, + 0x0a950, + 0x0b557, //1940-1949 + 0x06ca0, + 0x0b550, + 0x15355, + 0x04da0, + 0x0a5b0, + 0x14573, + 0x052b0, + 0x0a9a8, + 0x0e950, + 0x06aa0, //1950-1959 + 0x0aea6, + 0x0ab50, + 0x04b60, + 0x0aae4, + 0x0a570, + 0x05260, + 0x0f263, + 0x0d950, + 0x05b57, + 0x056a0, //1960-1969 + 0x096d0, + 0x04dd5, + 0x04ad0, + 0x0a4d0, + 0x0d4d4, + 0x0d250, + 0x0d558, + 0x0b540, + 0x0b6a0, + 0x195a6, //1970-1979 + 0x095b0, + 0x049b0, + 0x0a974, + 0x0a4b0, + 0x0b27a, + 0x06a50, + 0x06d40, + 0x0af46, + 0x0ab60, + 0x09570, //1980-1989 + 0x04af5, + 0x04970, + 0x064b0, + 0x074a3, + 0x0ea50, + 0x06b58, + 0x05ac0, + 0x0ab60, + 0x096d5, + 0x092e0, //1990-1999 + 0x0c960, + 0x0d954, + 0x0d4a0, + 0x0da50, + 0x07552, + 0x056a0, + 0x0abb7, + 0x025d0, + 0x092d0, + 0x0cab5, //2000-2009 + 0x0a950, + 0x0b4a0, + 0x0baa4, + 0x0ad50, + 0x055d9, + 0x04ba0, + 0x0a5b0, + 0x15176, + 0x052b0, + 0x0a930, //2010-2019 + 0x07954, + 0x06aa0, + 0x0ad50, + 0x05b52, + 0x04b60, + 0x0a6e6, + 0x0a4e0, + 0x0d260, + 0x0ea65, + 0x0d530, //2020-2029 + 0x05aa0, + 0x076a3, + 0x096d0, + 0x04afb, + 0x04ad0, + 0x0a4d0, + 0x1d0b6, + 0x0d250, + 0x0d520, + 0x0dd45, //2030-2039 + 0x0b5a0, + 0x056d0, + 0x055b2, + 0x049b0, + 0x0a577, + 0x0a4b0, + 0x0aa50, + 0x1b255, + 0x06d20, + 0x0ada0, //2040-2049 + /**Add By JJonline@JJonline.Cn**/ + 0x14b63, + 0x09370, + 0x049f8, + 0x04970, + 0x064b0, + 0x168a6, + 0x0ea50, + 0x06b20, + 0x1a6c4, + 0x0aae0, //2050-2059 + 0x0a2e0, + 0x0d2e3, + 0x0c960, + 0x0d557, + 0x0d4a0, + 0x0da50, + 0x05d55, + 0x056a0, + 0x0a6d0, + 0x055d4, //2060-2069 + 0x052d0, + 0x0a9b8, + 0x0a950, + 0x0b4a0, + 0x0b6a6, + 0x0ad50, + 0x055a0, + 0x0aba4, + 0x0a5b0, + 0x052b0, //2070-2079 + 0x0b273, + 0x06930, + 0x07337, + 0x06aa0, + 0x0ad50, + 0x14b55, + 0x04b60, + 0x0a570, + 0x054e4, + 0x0d160, //2080-2089 + 0x0e968, + 0x0d520, + 0x0daa0, + 0x16aa6, + 0x056d0, + 0x04ae0, + 0x0a9d4, + 0x0a2d0, + 0x0d150, + 0x0f252, //2090-2099 + 0x0d520 + ], //2100 + + /** + * 公历每个月份的天数普通表 + * @Array Of Property + * @return Number + */ + solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + + /** + * 天干地支之天干速查表 + * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"] + * @return Cn string + */ + Gan: [ + "\u7532", + "\u4e59", + "\u4e19", + "\u4e01", + "\u620a", + "\u5df1", + "\u5e9a", + "\u8f9b", + "\u58ec", + "\u7678" + ], + + /** + * 天干地支之地支速查表 + * @Array Of Property + * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"] + * @return Cn string + */ + Zhi: [ + "\u5b50", + "\u4e11", + "\u5bc5", + "\u536f", + "\u8fb0", + "\u5df3", + "\u5348", + "\u672a", + "\u7533", + "\u9149", + "\u620c", + "\u4ea5" + ], + + /** + * 天干地支之地支速查表<=>生肖 + * @Array Of Property + * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"] + * @return Cn string + */ + Animals: [ + "\u9f20", + "\u725b", + "\u864e", + "\u5154", + "\u9f99", + "\u86c7", + "\u9a6c", + "\u7f8a", + "\u7334", + "\u9e21", + "\u72d7", + "\u732a" + ], + + /** + * 24节气速查表 + * @Array Of Property + * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"] + * @return Cn string + */ + solarTerm: [ + "\u5c0f\u5bd2", + "\u5927\u5bd2", + "\u7acb\u6625", + "\u96e8\u6c34", + "\u60ca\u86f0", + "\u6625\u5206", + "\u6e05\u660e", + "\u8c37\u96e8", + "\u7acb\u590f", + "\u5c0f\u6ee1", + "\u8292\u79cd", + "\u590f\u81f3", + "\u5c0f\u6691", + "\u5927\u6691", + "\u7acb\u79cb", + "\u5904\u6691", + "\u767d\u9732", + "\u79cb\u5206", + "\u5bd2\u9732", + "\u971c\u964d", + "\u7acb\u51ac", + "\u5c0f\u96ea", + "\u5927\u96ea", + "\u51ac\u81f3" + ], + + /** + * 1900-2100各年的24节气日期速查表 + * @Array Of Property + * @return 0x string For splice + */ + sTermInfo: [ + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf97c3598082c95f8c965cc920f", + "97bd0b06bdb0722c965ce1cfcc920f", + "b027097bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf97c359801ec95f8c965cc920f", + "97bd0b06bdb0722c965ce1cfcc920f", + "b027097bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf97c359801ec95f8c965cc920f", + "97bd0b06bdb0722c965ce1cfcc920f", + "b027097bd097c36b0b6fc9274c91aa", + "9778397bd19801ec9210c965cc920e", + "97b6b97bd19801ec95f8c965cc920f", + "97bd09801d98082c95f8e1cfcc920f", + "97bd097bd097c36b0b6fc9210c8dc2", + "9778397bd197c36c9210c9274c91aa", + "97b6b97bd19801ec95f8c965cc920e", + "97bd09801d98082c95f8e1cfcc920f", + "97bd097bd097c36b0b6fc9210c8dc2", + "9778397bd097c36c9210c9274c91aa", + "97b6b97bd19801ec95f8c965cc920e", + "97bcf97c3598082c95f8e1cfcc920f", + "97bd097bd097c36b0b6fc9210c8dc2", + "9778397bd097c36c9210c9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf97c3598082c95f8c965cc920f", + "97bd097bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf97c3598082c95f8c965cc920f", + "97bd097bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf97c359801ec95f8c965cc920f", + "97bd097bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf97c359801ec95f8c965cc920f", + "97bd097bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf97c359801ec95f8c965cc920f", + "97bd097bd07f595b0b6fc920fb0722", + "9778397bd097c36b0b6fc9210c8dc2", + "9778397bd19801ec9210c9274c920e", + "97b6b97bd19801ec95f8c965cc920f", + "97bd07f5307f595b0b0bc920fb0722", + "7f0e397bd097c36b0b6fc9210c8dc2", + "9778397bd097c36c9210c9274c920e", + "97b6b97bd19801ec95f8c965cc920f", + "97bd07f5307f595b0b0bc920fb0722", + "7f0e397bd097c36b0b6fc9210c8dc2", + "9778397bd097c36c9210c9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bd07f1487f595b0b0bc920fb0722", + "7f0e397bd097c36b0b6fc9210c8dc2", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf7f1487f595b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf7f1487f595b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf7f1487f531b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c965cc920e", + "97bcf7f1487f531b0b0bb0b6fb0722", + "7f0e397bd07f595b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b97bd19801ec9210c9274c920e", + "97bcf7f0e47f531b0b0bb0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "9778397bd097c36b0b6fc9210c91aa", + "97b6b97bd197c36c9210c9274c920e", + "97bcf7f0e47f531b0b0bb0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "9778397bd097c36b0b6fc9210c8dc2", + "9778397bd097c36c9210c9274c920e", + "97b6b7f0e47f531b0723b0b6fb0722", + "7f0e37f5307f595b0b0bc920fb0722", + "7f0e397bd097c36b0b6fc9210c8dc2", + "9778397bd097c36b0b70c9274c91aa", + "97b6b7f0e47f531b0723b0b6fb0721", + "7f0e37f1487f595b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc9210c8dc2", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f595b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "9778397bd097c36b0b6fc9274c91aa", + "97b6b7f0e47f531b0723b0787b0721", + "7f0e27f0e47f531b0b0bb0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "9778397bd097c36b0b6fc9210c91aa", + "97b6b7f0e47f149b0723b0787b0721", + "7f0e27f0e47f531b0723b0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "9778397bd097c36b0b6fc9210c8dc2", + "977837f0e37f149b0723b0787b0721", + "7f07e7f0e47f531b0723b0b6fb0722", + "7f0e37f5307f595b0b0bc920fb0722", + "7f0e397bd097c35b0b6fc9210c8dc2", + "977837f0e37f14998082b0787b0721", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e37f1487f595b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc9210c8dc2", + "977837f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc920fb0722", + "977837f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e397bd097c35b0b6fc920fb0722", + "977837f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "977837f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "977837f0e37f14998082b0787b06bd", + "7f07e7f0e47f149b0723b0787b0721", + "7f0e27f0e47f531b0b0bb0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "977837f0e37f14998082b0723b06bd", + "7f07e7f0e37f149b0723b0787b0721", + "7f0e27f0e47f531b0723b0b6fb0722", + "7f0e397bd07f595b0b0bc920fb0722", + "977837f0e37f14898082b0723b02d5", + "7ec967f0e37f14998082b0787b0721", + "7f07e7f0e47f531b0723b0b6fb0722", + "7f0e37f1487f595b0b0bb0b6fb0722", + "7f0e37f0e37f14898082b0723b02d5", + "7ec967f0e37f14998082b0787b0721", + "7f07e7f0e47f531b0723b0b6fb0722", + "7f0e37f1487f531b0b0bb0b6fb0722", + "7f0e37f0e37f14898082b0723b02d5", + "7ec967f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e37f1487f531b0b0bb0b6fb0722", + "7f0e37f0e37f14898082b072297c35", + "7ec967f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e37f0e37f14898082b072297c35", + "7ec967f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e37f0e366aa89801eb072297c35", + "7ec967f0e37f14998082b0787b06bd", + "7f07e7f0e47f149b0723b0787b0721", + "7f0e27f1487f531b0b0bb0b6fb0722", + "7f0e37f0e366aa89801eb072297c35", + "7ec967f0e37f14998082b0723b06bd", + "7f07e7f0e47f149b0723b0787b0721", + "7f0e27f0e47f531b0723b0b6fb0722", + "7f0e37f0e366aa89801eb072297c35", + "7ec967f0e37f14998082b0723b06bd", + "7f07e7f0e37f14998083b0787b0721", + "7f0e27f0e47f531b0723b0b6fb0722", + "7f0e37f0e366aa89801eb072297c35", + "7ec967f0e37f14898082b0723b02d5", + "7f07e7f0e37f14998082b0787b0721", + "7f07e7f0e47f531b0723b0b6fb0722", + "7f0e36665b66aa89801e9808297c35", + "665f67f0e37f14898082b0723b02d5", + "7ec967f0e37f14998082b0787b0721", + "7f07e7f0e47f531b0723b0b6fb0722", + "7f0e36665b66a449801e9808297c35", + "665f67f0e37f14898082b0723b02d5", + "7ec967f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e36665b66a449801e9808297c35", + "665f67f0e37f14898082b072297c35", + "7ec967f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e26665b66a449801e9808297c35", + "665f67f0e37f1489801eb072297c35", + "7ec967f0e37f14998082b0787b06bd", + "7f07e7f0e47f531b0723b0b6fb0721", + "7f0e27f1487f531b0b0bb0b6fb0722" + ], + + /** + * 数字转中文速查表 + * @Array Of Property + * @trans ['日','一','二','三','四','五','六','七','八','九','十'] + * @return Cn string + */ + nStr1: [ + "\u65e5", + "\u4e00", + "\u4e8c", + "\u4e09", + "\u56db", + "\u4e94", + "\u516d", + "\u4e03", + "\u516b", + "\u4e5d", + "\u5341" + ], + + /** + * 日期转农历称呼速查表 + * @Array Of Property + * @trans ['初','十','廿','卅'] + * @return Cn string + */ + nStr2: ["\u521d", "\u5341", "\u5eff", "\u5345"], + + /** + * 月份转农历称呼速查表 + * @Array Of Property + * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊'] + * @return Cn string + */ + nStr3: [ + "\u6b63", + "\u4e8c", + "\u4e09", + "\u56db", + "\u4e94", + "\u516d", + "\u4e03", + "\u516b", + "\u4e5d", + "\u5341", + "\u51ac", + "\u814a" + ], + + /** + * 返回农历y年一整年的总天数 + * @param lunar Year + * @return Number + * @eg:var count = calendar.lYearDays(1987) ;//count=387 + */ + lYearDays: function(y) { + var i, + sum = 348; + for (i = 0x8000; i > 0x8; i >>= 1) { + sum += this.lunarInfo[y - 1900] & i ? 1 : 0; + } + return sum + this.leapDays(y); + }, + + /** + * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0 + * @param lunar Year + * @return Number (0-12) + * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6 + */ + leapMonth: function(y) { + //闰字编码 \u95f0 + return this.lunarInfo[y - 1900] & 0xf; + }, + + /** + * 返回农历y年闰月的天数 若该年没有闰月则返回0 + * @param lunar Year + * @return Number (0、29、30) + * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29 + */ + leapDays: function(y) { + if (this.leapMonth(y)) { + return this.lunarInfo[y - 1900] & 0x10000 ? 30 : 29; + } + return 0; + }, + + /** + * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法 + * @param lunar Year + * @return Number (-1、29、30) + * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29 + */ + monthDays: function(y, m) { + if (m > 12 || m < 1) { + return -1; + } //月份参数从1至12,参数错误返回-1 + return this.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29; + }, + + /** + * 返回公历(!)y年m月的天数 + * @param solar Year + * @return Number (-1、28、29、30、31) + * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30 + */ + solarDays: function(y, m) { + if (m > 12 || m < 1) { + return -1; + } //若参数错误 返回-1 + var ms = m - 1; + if (ms === 1) { + //2月份的闰平规律测算后确认返回28或29 + return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 ? 29 : 28; + } else { + return this.solarMonth[ms]; + } + }, + + /** + * 农历年份转换为干支纪年 + * @param lYear 农历年的年份数 + * @return Cn string + */ + toGanZhiYear: function(lYear) { + var ganKey = (lYear - 3) % 10; + var zhiKey = (lYear - 3) % 12; + if (ganKey === 0) ganKey = 10; //如果余数为0则为最后一个天干 + if (zhiKey === 0) zhiKey = 12; //如果余数为0则为最后一个地支 + return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]; + }, + + /** + * 公历月、日判断所属星座 + * @param cMonth [description] + * @param cDay [description] + * @return Cn string + */ + toAstro: function(cMonth, cDay) { + var s = + "\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf"; + var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]; + return ( + s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + "\u5ea7" + ); //座 + }, + + /** + * 传入offset偏移量返回干支 + * @param offset 相对甲子的偏移量 + * @return Cn string + */ + toGanZhi: function(offset) { + return this.Gan[offset % 10] + this.Zhi[offset % 12]; + }, + + /** + * 传入公历(!)y年获得该年第n个节气的公历日期 + * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起 + * @return day Number + * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春 + */ + getTerm: function(y, n) { + if (y < 1900 || y > 2100) { + return -1; + } + if (n < 1 || n > 24) { + return -1; + } + var _table = this.sTermInfo[y - 1900]; + var _info = [ + parseInt("0x" + _table.substr(0, 5)).toString(), + parseInt("0x" + _table.substr(5, 5)).toString(), + parseInt("0x" + _table.substr(10, 5)).toString(), + parseInt("0x" + _table.substr(15, 5)).toString(), + parseInt("0x" + _table.substr(20, 5)).toString(), + parseInt("0x" + _table.substr(25, 5)).toString() + ]; + var _calday = [ + _info[0].substr(0, 1), + _info[0].substr(1, 2), + _info[0].substr(3, 1), + _info[0].substr(4, 2), + + _info[1].substr(0, 1), + _info[1].substr(1, 2), + _info[1].substr(3, 1), + _info[1].substr(4, 2), + + _info[2].substr(0, 1), + _info[2].substr(1, 2), + _info[2].substr(3, 1), + _info[2].substr(4, 2), + + _info[3].substr(0, 1), + _info[3].substr(1, 2), + _info[3].substr(3, 1), + _info[3].substr(4, 2), + + _info[4].substr(0, 1), + _info[4].substr(1, 2), + _info[4].substr(3, 1), + _info[4].substr(4, 2), + + _info[5].substr(0, 1), + _info[5].substr(1, 2), + _info[5].substr(3, 1), + _info[5].substr(4, 2) + ]; + return parseInt(_calday[n - 1]); + }, + + /** + * 传入农历数字月份返回汉语通俗表示法 + * @param lunar month + * @return Cn string + * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月' + */ + toChinaMonth: function(m) { + // 月 => \u6708 + if (m > 12 || m < 1) { + return -1; + } //若参数错误 返回-1 + var s = this.nStr3[m - 1]; + s += "\u6708"; //加上月字 + return s; + }, + + /** + * 传入农历日期数字返回汉字表示法 + * @param lunar day + * @return Cn string + * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一' + */ + toChinaDay: function(d) { + //日 => \u65e5 + var s; + switch (d) { + case 10: + s = "\u521d\u5341"; + break; + case 20: + s = "\u4e8c\u5341"; + break; + case 30: + s = "\u4e09\u5341"; + break; + default: + s = this.nStr2[Math.floor(d / 10)]; + s += this.nStr1[d % 10]; + } + return s; + }, + + /** + * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春” + * @param y year + * @return Cn string + * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔' + */ + getAnimal: function(y) { + return this.Animals[(y - 4) % 12]; + }, + + /** + * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON + * @param y solar year + * @param m solar month + * @param d solar day + * @return JSON object + * @eg:console.log(calendar.solar2lunar(1987,11,01)); + */ + solar2lunar: function(y, m, d) { + //参数区间1900.1.31~2100.12.31 + //年份限定、上限 + if (y < 1900 || y > 2100) { + return -1; // undefined转换为数字变为NaN + } + //公历传参最下限 + if (y === 1900 && m === 1 && d < 31) { + return -1; + } + //未传参 获得当天 + var objDate; + if (!y) { + objDate = new Date(); + } else { + objDate = new Date(y, parseInt(m) - 1, d); + } + var i, + leap = 0, + temp = 0; + //修正ymd参数 + y = objDate.getFullYear(); + (m = objDate.getMonth() + 1), (d = objDate.getDate()); + var offset = + (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - + Date.UTC(1900, 0, 31)) / + 86400000; + for (i = 1900; i < 2101 && offset > 0; i++) { + temp = this.lYearDays(i); + offset -= temp; + } + if (offset < 0) { + offset += temp; + i--; + } + + //是否今天 + var isTodayObj = new Date(), + isToday = false; + if ( + isTodayObj.getFullYear() === y && + isTodayObj.getMonth() + 1 === m && + isTodayObj.getDate() === d + ) { + isToday = true; + } + //星期几 + var nWeek = objDate.getDay(), + cWeek = this.nStr1[nWeek]; + //数字表示周几顺应天朝周一开始的惯例 + if (nWeek === 0) { + nWeek = 7; + } + //农历年 + var year = i; + leap = this.leapMonth(i); //闰哪个月 + var isLeap = false; + + //效验闰月 + for (i = 1; i < 13 && offset > 0; i++) { + //闰月 + if (leap > 0 && i === leap + 1 && isLeap === false) { + --i; + isLeap = true; + temp = this.leapDays(year); //计算农历闰月天数 + } else { + temp = this.monthDays(year, i); //计算农历普通月天数 + } + //解除闰月 + if (isLeap === true && i === leap + 1) { + isLeap = false; + } + offset -= temp; + } + // 闰月导致数组下标重叠取反 + if (offset === 0 && leap > 0 && i === leap + 1) { + if (isLeap) { + isLeap = false; + } else { + isLeap = true; + --i; + } + } + if (offset < 0) { + offset += temp; + --i; + } + //农历月 + var month = i; + //农历日 + var day = offset + 1; + //天干地支处理 + var sm = m - 1; + var gzY = this.toGanZhiYear(year); + + // 当月的两个节气 + // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year` + var firstNode = this.getTerm(y, m * 2 - 1); //返回当月「节」为几日开始 + var secondNode = this.getTerm(y, m * 2); //返回当月「节」为几日开始 + + // 依据12节气修正干支月 + var gzM = this.toGanZhi((y - 1900) * 12 + m + 11); + if (d >= firstNode) { + gzM = this.toGanZhi((y - 1900) * 12 + m + 12); + } + + //传入的日期的节气与否 + var isTerm = false; + var Term = null; + if (firstNode === d) { + isTerm = true; + Term = this.solarTerm[m * 2 - 2]; + } + if (secondNode === d) { + isTerm = true; + Term = this.solarTerm[m * 2 - 1]; + } + //日柱 当月一日与 1900/1/1 相差天数 + var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10; + var gzD = this.toGanZhi(dayCyclical + d - 1); + //该日期所属的星座 + var astro = this.toAstro(m, d); + + return { + lYear: year, + lMonth: month, + lDay: day, + Animal: this.getAnimal(year), + IMonthCn: (isLeap ? "\u95f0" : "") + this.toChinaMonth(month), + IDayCn: this.toChinaDay(day), + cYear: y, + cMonth: m, + cDay: d, + gzYear: gzY, + gzMonth: gzM, + gzDay: gzD, + isToday: isToday, + isLeap: isLeap, + nWeek: nWeek, + ncWeek: "\u661f\u671f" + cWeek, + isTerm: isTerm, + Term: Term, + astro: astro + }; + }, + + /** + * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON + * @param y lunar year + * @param m lunar month + * @param d lunar day + * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可] + * @return JSON object + * @eg:console.log(calendar.lunar2solar(1987,9,10)); + */ + lunar2solar: function(y, m, d, isLeapMonth) { + //参数区间1900.1.31~2100.12.1 + isLeapMonth = !!isLeapMonth; + // var leapOffset = 0; + var leapMonth = this.leapMonth(y); + // var leapDay = this.leapDays(y); + if (isLeapMonth && leapMonth !== m) { + return -1; + } //传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同 + if ( + (y === 2100 && m === 12 && d > 1) || + (y === 1900 && m === 1 && d < 31) + ) { + return -1; + } //超出了最大极限值 + var day = this.monthDays(y, m); + var _day = day; + //bugFix 2016-9-25 + //if month is leap, _day use leapDays method + if (isLeapMonth) { + _day = this.leapDays(y, m); + } + if (y < 1900 || y > 2100 || d > _day) { + return -1; + } //参数合法性效验 + + //计算农历的时间差 + var offset = 0; + for (var i = 1900; i < y; i++) { + offset += this.lYearDays(i); + } + var leap = 0, + isAdd = false; + for (i = 1; i < m; i++) { + leap = this.leapMonth(y); + if (!isAdd) { + //处理闰月 + if (leap <= i && leap > 0) { + offset += this.leapDays(y); + isAdd = true; + } + } + offset += this.monthDays(y, i); + } + //转换闰月农历 需补充该年闰月的前一个月的时差 + if (isLeapMonth) { + offset += day; + } + //1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) + var stmap = Date.UTC(1900, 1, 30, 0, 0, 0); + var calObj = new Date((offset + d - 31) * 86400000 + stmap); + var cY = calObj.getUTCFullYear(); + var cM = calObj.getUTCMonth() + 1; + var cD = calObj.getUTCDate(); + + return this.solar2lunar(cY, cM, cD); + } +}; +export { calendar }; diff --git a/jvue-front/src/util/DateUtil.js b/jvue-front/src/util/DateUtil.js new file mode 100644 index 0000000..53c73e5 --- /dev/null +++ b/jvue-front/src/util/DateUtil.js @@ -0,0 +1,87 @@ +/** + * DateUtil.js + * + *@author Terwer + *@version 1.0 + *2019/2/28 9:47 + **/ +import { calendar } from "./Calendar"; + +const lunar = calendar.solar2lunar(); + +/** + * 根据日期获取星期几 + * @returns {string} 星期 + */ +var getWeekByDay = function() { + var day = new Date(); + var today = [ + "星期日", + "星期一", + "星期二", + "星期三", + "星期四", + "星期五", + "星期六" + ]; //创建星期数组 + // console.log(today[day.getDay()]); + return today[day.getDay()]; //返一个星期中的某一天,其中0为星期日 +}; + +/** + * 获取星期 + * @returns {string} + */ +var getClientTime = function() { + //获取客户端时间 + var now = new Date(); + var currDatetime = ""; + // currDatetime += now.getFullYear() + "年"; + // currDatetime += + // now.getMonth() + 1 > 9 ? now.getMonth() + 1 : "0" + (now.getMonth() + 1); + // currDatetime += "月"; + // currDatetime += now.getDate() > 9 ? now.getDate() : "0" + now.getDate(); + // currDatetime += "日 "; + currDatetime += now.getHours() > 9 ? now.getHours() : "0" + now.getHours(); + currDatetime += ":"; + currDatetime += + now.getMinutes() > 9 ? now.getMinutes() : "0" + now.getMinutes(); + currDatetime += ":"; + currDatetime += + now.getSeconds() > 9 ? now.getSeconds() : "0" + now.getSeconds(); + return currDatetime; +}; + +var getPopTime = function() { + var popTime = + "阳历:" + + lunar.cYear + + "年" + + lunar.cMonth + + "月" + + lunar.cDay + + "日(" + + lunar.astro + + ")"; + return popTime; +}; + +var getTradTime = function() { + var tradTime = "农历:" + lunar.lYear + "年" + lunar.IMonthCn + lunar.IDayCn; + return tradTime; +}; + +var getShengXiao = function() { + var shengxiao = + lunar.gzYear + + "年" + + lunar.gzMonth + + "月" + + lunar.gzDay + + "日(" + + lunar.Animal + + "年)"; + return shengxiao; +}; + +export { getClientTime, getPopTime, getTradTime, getShengXiao, getWeekByDay }; diff --git a/jvue-front/src/util/dom.js b/jvue-front/src/util/dom.js new file mode 100644 index 0000000..777ce22 --- /dev/null +++ b/jvue-front/src/util/dom.js @@ -0,0 +1,8 @@ +/** + * dom.js + * + * @author Terwer + * @version 1.0 + * 19-2-28 上午12:28 + **/ +export const inBrowser = typeof window !== "undefined"; diff --git a/jvue-front/src/util/logger.js b/jvue-front/src/util/logger.js new file mode 100644 index 0000000..b2af3bf --- /dev/null +++ b/jvue-front/src/util/logger.js @@ -0,0 +1,44 @@ +/** + * logger + * + * @author Terwer + * @version 1.0 + * 19-2-27 下午11:22 + **/ +global.loggerName = "default"; +const isDebugEnabled = process.env.VUE_APP_DEBUG === "true"; +const isInfoEnabled = process.env.VUE_APP_INFO === "true"; +const isErrorEnabled = process.env.VUE_APP_ERROR === "true"; +console.log( + "isDebugEnabled,isInfoEnabled,isErrorEnabled=>", + `${isDebugEnabled},${isInfoEnabled},${isErrorEnabled}` +); + +const debug = log => { + if (isDebugEnabled) { + console.warn("[", global.loggerName, "]", log); + } +}; + +const info = log => { + if (isInfoEnabled) { + console.log("[", global.loggerName, "]", log); + } +}; + +const error = log => { + if (isErrorEnabled) { + console.error("[", global.loggerName, "]", log); + } +}; + +let logger = { + debug, + info, + error +}; + +export const getLogger = name => { + global.loggerName = name; + return logger; +}; diff --git a/jvue-front/src/util/storage.js b/jvue-front/src/util/storage.js new file mode 100644 index 0000000..887e472 --- /dev/null +++ b/jvue-front/src/util/storage.js @@ -0,0 +1,90 @@ +/** + * storage.js + * + * @author Terwer + * @version 1.0 + * 19-2-28 上午12:22 + **/ +import { getLogger } from "./logger"; +const logger = getLogger("util/storage"); +const CircularJSON = require("circular-json"); +import { isEmptyOrUndefined } from "./string"; +import { inBrowser } from "../util/dom"; +import Vue from "vue"; + +/** + * 设置Session缓存 + * @param key key + * @param value value + */ +const setSessionStorage = (key, value) => { + console.log("Vue.$sessionStorage.set=>key:", key); + console.log("Vue.$sessionStorage.set=>value:", value); + Vue.$sessionStorage.set(key, value); +}; + +/** + * 获取Session缓存 + * @param key key + * @returns {*} + */ +// const getSessionStorage = key => { +// return getSessionStorageOrDefault(key, ""); +// }; + +/** + * 获取Session缓存带默认值 + * @param key + * @param val + * @returns string + */ +const getSessionStorageOrDefault = (key, val) => { + const value = Vue.$sessionStorage.get(key); + console.log("Vue.$sessionStorage.get=>key:", key); + // console.log("Vue.$sessionStorage.get=>value:", value); + return isEmptyOrUndefined(value) ? val : value; +}; + +const setSession = (key, value) => { + logger.debug("process.env.SSR_ENV=>", process.env.SSR_ENV); + if (inBrowser) { + // 客户端存储数据 + logger.debug("setSession to $sessionStorage"); + setSessionStorage(key, value); + } else { + // 服务端设置Session + logger.debug("setSession to server"); + global.setSessionCallback(key, value); + } +}; + +const getSession = (key, val) => { + let data = ""; + if (inBrowser) { + // 客户端获取数据 + // 优先获取SessionStorage,因为这里是最新更新的数据,点击客户端路由就会更新 + data = getSessionStorageOrDefault(key, val); + logger.debug("get data from sessionStorage"); + // logger.debug(data); + // 没有Session取window.__INITIAL_STATE__,这里只有触发服务端渲染才会更新 + logger.debug("storage window.__INITIAL_STATE__=>"); + logger.debug(window.__INITIAL_STATE__); + // 如果Session空,就从window.__INITIAL_STATE__获取值 + const isEmpty = data === "[]" || data === "{}"; + if (isEmpty && !isEmptyOrUndefined(window.__INITIAL_STATE__)) { + logger.debug("get data from window.__INITIAL_STATE__"); + const initDataMap = window.__INITIAL_STATE__[0]; + const curStr = CircularJSON.parse(initDataMap[key]); + console.log(typeof curStr); + data = CircularJSON.stringify(curStr); + } + } else { + // 服务端获取Session + data = global.getSessionCallback(key); + logger.debug("getSession from server"); + } + logger.debug("getSession data success"); + return data; +}; + +export { setSession, getSession }; diff --git a/jvue-front/src/util/string.js b/jvue-front/src/util/string.js new file mode 100644 index 0000000..d63be50 --- /dev/null +++ b/jvue-front/src/util/string.js @@ -0,0 +1,16 @@ +/** + * string.js + * + * @author Terwer + * @version 1.0 + * 19-2-28 上午12:23 + **/ +const isEmptyOrUndefined = v => { + return ( + typeof v == "undefined" || + v == null || + (typeof v == "string" && (v === "" || v.trim() === "")) + ); +}; + +export { isEmptyOrUndefined }; diff --git a/jvue-front/src/views/About.vue b/jvue-front/src/views/About.vue index 3fa2807..70ba91f 100644 --- a/jvue-front/src/views/About.vue +++ b/jvue-front/src/views/About.vue @@ -1,5 +1,111 @@ + + + + diff --git a/jvue-front/src/views/Category.vue b/jvue-front/src/views/Category.vue new file mode 100644 index 0000000..0764eca --- /dev/null +++ b/jvue-front/src/views/Category.vue @@ -0,0 +1,72 @@ + + + + diff --git a/jvue-front/src/views/Detail.vue b/jvue-front/src/views/Detail.vue new file mode 100644 index 0000000..4eac254 --- /dev/null +++ b/jvue-front/src/views/Detail.vue @@ -0,0 +1,233 @@ + + + + + diff --git a/jvue-front/src/views/Home.vue b/jvue-front/src/views/Home.vue index 05494f6..c7a2864 100644 --- a/jvue-front/src/views/Home.vue +++ b/jvue-front/src/views/Home.vue @@ -1,18 +1,202 @@ + + diff --git a/jvue-front/src/views/Login.vue b/jvue-front/src/views/Login.vue new file mode 100644 index 0000000..dec1d2d --- /dev/null +++ b/jvue-front/src/views/Login.vue @@ -0,0 +1,14 @@ + + + + + diff --git a/jvue-front/src/views/Register.vue b/jvue-front/src/views/Register.vue new file mode 100644 index 0000000..1e5b6ed --- /dev/null +++ b/jvue-front/src/views/Register.vue @@ -0,0 +1,14 @@ + + + + + diff --git a/jvue-front/src/views/admin/AdminHome.vue b/jvue-front/src/views/admin/AdminHome.vue new file mode 100644 index 0000000..c978c61 --- /dev/null +++ b/jvue-front/src/views/admin/AdminHome.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/jvue-front/src/views/admin/AdminLogin.vue b/jvue-front/src/views/admin/AdminLogin.vue new file mode 100644 index 0000000..1f5dfca --- /dev/null +++ b/jvue-front/src/views/admin/AdminLogin.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/jvue-front/src/views/admin/Dashboard.vue b/jvue-front/src/views/admin/Dashboard.vue new file mode 100644 index 0000000..11f1f49 --- /dev/null +++ b/jvue-front/src/views/admin/Dashboard.vue @@ -0,0 +1,283 @@ + + + + + diff --git a/jvue-front/src/views/admin/postManage/PostEdit.vue b/jvue-front/src/views/admin/postManage/PostEdit.vue new file mode 100644 index 0000000..8a91474 --- /dev/null +++ b/jvue-front/src/views/admin/postManage/PostEdit.vue @@ -0,0 +1,72 @@ + + + diff --git a/jvue-front/src/views/admin/postManage/PostList.vue b/jvue-front/src/views/admin/postManage/PostList.vue new file mode 100644 index 0000000..743c500 --- /dev/null +++ b/jvue-front/src/views/admin/postManage/PostList.vue @@ -0,0 +1,3 @@ + diff --git a/jvue-front/tests/dev-server.js b/jvue-front/tests/dev-server.js new file mode 100644 index 0000000..1308dff --- /dev/null +++ b/jvue-front/tests/dev-server.js @@ -0,0 +1,94 @@ +/** + * dev server with express + * + *@author Terwer + *@version 1.0 + *2019/2/27 15:01 + **/ +// 设置渲染模式 +process.env.VUE_ENV = "server"; +process.on("unhandledRejection", function(reason, p) { + console.log("Unhandled Rejection at: Promise", p, "reason:", reason); +}); + +const CircularJSON = require("circular-json"); + +const path = require("path"); +const resolvePath = file => path.resolve(__dirname, file); + +const express = require("express"); +const port = 3000; + +// Configure your application to use Thymeleaf via the express-thymeleaf module +let app = express(); +const render = require("../dist/server"); + +// 静态资源 +// const favicon = require("serve-favicon"); +const serve = path => express.static(resolvePath(path)); +// app.use(favicon("./public/favicon.ico")); +// app.use("/", (req, res, next) => { +// if (process.env.NODE_ENV === "development") { +// const result = req.url.match(/\.(html)$/); +// console.log("req.url=>",req.url) +// console.log("result=>",result) +// if (result) { +// return res.status(403).end("403 Forbidden"); +// } +// } +// next(); +// }); +app.use("/", serve("../dist", false)); +app.use("/js", serve("../dist/js", false)); +app.use("/css", serve("../dist/css", false)); +app.use("/img", serve("../dist/img", false)); + +// 在服务器处理函数中…… +app.get("*", (req, res) => { + // get context + const seo = { + title: "title", + meta: { + keywords: "keywords", + description: "description" + } + }; + const context = CircularJSON.stringify(Object.assign({ url: req.url }, seo)); + + // 这里无需传入一个应用程序,因为在执行 bundle 时已经自动创建过。 + // 现在我们的服务器与应用程序已经解耦! + const promise = render.renderServer(context); + + promise + .then((html, err) => { + if (err) { + console.log("err=>", err); + res.send(err); + return; + } + console.log("html=>", html); + res.send(html); + }) + .catch(rejected => { + console.log("rejected=>", rejected); + res.send(rejected); + }); +}); + +// start http server +app.listen(port, () => { + console.log(`dev-server is listening on port ${port}...`); +}); + +// deal with callback +global.setSessionCallback = (key, value) => { + console.log("key=>", key); + console.log("value=>", value); +}; + +global.getSessionCallback = key => { + const value = CircularJSON.stringify([]); + console.log("getSessionCallback key=>", key); + console.log("getSessionCallback value=>", value); + return value; +}; diff --git a/jvue-front/tests/e2e/custom-assertions/elementCount.js b/jvue-front/tests/e2e/custom-assertions/elementCount.js deleted file mode 100644 index 6fb13ff..0000000 --- a/jvue-front/tests/e2e/custom-assertions/elementCount.js +++ /dev/null @@ -1,19 +0,0 @@ -// A custom Nightwatch assertion. -// The assertion name is the filename. -// Example usage: -// -// browser.assert.elementCount(selector, count) -// -// For more information on custom assertions see: -// http://nightwatchjs.org/guide#writing-custom-assertions - -exports.assertion = function elementCount(selector, count) { - this.message = `Testing if element <${selector}> has count: ${count}`; - this.expected = count; - this.pass = val => val === count; - this.value = res => res.value; - function evaluator(_selector) { - return document.querySelectorAll(_selector).length; - } - this.command = cb => this.api.execute(evaluator, [selector], cb); -}; diff --git a/jvue-front/tests/e2e/specs/test.js b/jvue-front/tests/e2e/specs/test.js deleted file mode 100644 index f10427a..0000000 --- a/jvue-front/tests/e2e/specs/test.js +++ /dev/null @@ -1,14 +0,0 @@ -// For authoring Nightwatch tests, see -// http://nightwatchjs.org/guide#usage - -module.exports = { - "default e2e tests": browser => { - browser - .url(process.env.VUE_DEV_SERVER_URL) - .waitForElementVisible("#app", 5000) - .assert.elementPresent(".hello") - .assert.containsText("h1", "Welcome to Your Vue.js App") - .assert.elementCount("img", 1) - .end(); - } -}; diff --git a/jvue-front/tests/unit/.eslintrc.js b/jvue-front/tests/unit/.eslintrc.js deleted file mode 100644 index 3600451..0000000 --- a/jvue-front/tests/unit/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - env: { - jest: true - } -}; diff --git a/jvue-front/tests/unit/example.spec.js b/jvue-front/tests/unit/example.spec.js deleted file mode 100644 index a846fbd..0000000 --- a/jvue-front/tests/unit/example.spec.js +++ /dev/null @@ -1,12 +0,0 @@ -import { shallowMount } from "@vue/test-utils"; -import HelloWorld from "@/components/HelloWorld.vue"; - -describe("HelloWorld.vue", () => { - it("renders props.msg when passed", () => { - const msg = "new message"; - const wrapper = shallowMount(HelloWorld, { - propsData: { msg } - }); - expect(wrapper.text()).toMatch(msg); - }); -}); diff --git a/jvue-front/tests/v8-server.js b/jvue-front/tests/v8-server.js new file mode 100644 index 0000000..53cb623 --- /dev/null +++ b/jvue-front/tests/v8-server.js @@ -0,0 +1,52 @@ +/** + * v8-server.js + * + *@author Terwer + *@version 1.0 + *2019/2/27 15:01 + **/ +// 设置渲染模式 +process.env.SSR_ENV = "server"; +process.env.VUE_ENV = "server"; +process.env.NODE_ENV = "production"; +process.on("unhandledRejection", function(reason, p) { + console.log("Unhandled Rejection at: Promise", p, "reason:", reason); +}); + +const CircularJSON = require("circular-json"); + +const render = require("../dist/server"); + +// get context +const seo = { + title: "title", + meta: { + keywords: "keywords", + description: "description" + } +}; +const context = CircularJSON.stringify(Object.assign({ url: "/" }, seo)); + +// deal with callback +global.renderServerCallback = (err, html) => { + // 处理异常…… + if (err) { + console.log("err=>", err); + return; + } + console.log("html=>", html); +}; + +global.setSessionCallback = (key, value) => { + console.log("key=>", key); + console.log("value=>", value); +}; + +global.getSessionCallback = key => { + const value = CircularJSON.stringify([]); + console.log("getSessionCallback key=>", key); + console.log("getSessionCallback value=>", value); + return value; +}; + +render.renderServer(context, global.renderServerCallback); diff --git a/jvue-front/vue.config.js b/jvue-front/vue.config.js new file mode 100644 index 0000000..c97ab2a --- /dev/null +++ b/jvue-front/vue.config.js @@ -0,0 +1,137 @@ +/** + * vue.config.js + * + * @author Terwer + * @version 1.0 + * 19-2-26 下午10:40 + **/ +const pkg = require("./package.json"); +const nodeExternals = require("webpack-node-externals"); +const VueSSRClientPlugin = require("vue-server-renderer/client-plugin"); +const VueSSRServerPlugin = require("vue-server-renderer/server-plugin"); + +module.exports = { + /** + * 部署应用包时的基本 URL。用法和 webpack 本身的 output.publicPath 一致, + * 但是 Vue CLI 在一些其他地方也需要用到这个值,所以请始终使用 publicPath + * 而不要直接修改 webpack 的 output.publicPath。 + */ + publicPath: process.env.VUE_APP_PUBLIC_PATH, + /** + * 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码。 + * https://cli.vuejs.org/zh/config/#lintonsave + */ + lintOnSave: true, + + // 指定生成的 index.html 的输出路径 (相对于 outputDir)。 + // 也可以是一个绝对路径 + // 默认index.html,修改之后,只有生产环境才会生效 + // indexPath: "index.html", + + // https://cli.vuejs.org/zh/config/#configurewebpack + configureWebpack: config => { + // 解决Invalid Host header + config.devServer.set('disableHostCheck', true); + console.log("\nprocess.env.SSR_ENV=>", process.env.SSR_ENV); + switch (process.env.SSR_ENV) { + case "client": { + // 客户端配置 (Client Config) + // https://ssr.vuejs.org/zh/guide/build-config.html#客户端配置-client-config + console.log("客户端配置"); + + // 将 entry 指向应用程序的 client entry 文件 + config.entry = "./src/entry-client.js"; + + // 重要信息:这将 webpack 运行时分离到一个引导 chunk 中, + // 以便可以在之后正确注入异步 chunk。 + // 这也为你的 应用程序/vendor 代码提供了更好的缓存。 + //webpack4的用法:https://github.com/webpack/webpack/issues/6357 + // config.optimization = { + // splitChunks: { + // chunks: "all" + // } + // }; + + // 此插件在输出目录中 + // 生成 `vue-ssr-client-manifest.json`。 + config.plugins.push(new VueSSRClientPlugin()); + break; + } + case "server": { + // 服务器配置 (Server Config) + // https://ssr.vuejs.org/zh/guide/build-config.html#服务器配置-server-config + console.log("服务器配置"); + + // 将 entry 指向应用程序的 server entry 文件 + config.entry = "./src/entry-server.js"; + + // 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import), + // 并且还会在编译 Vue 组件时, + // 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。 + config.target = "node"; + + // 对 bundle renderer 提供 source map 支持 + config.devtool = "source-map"; + + // 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports) + config.output.libraryTarget = "commonjs2"; + + // https://webpack.js.org/configuration/externals/#function + // https://github.com/liady/webpack-node-externals + // 外置化应用程序依赖模块。可以使服务器构建速度更快, + // 并生成较小的 bundle 文件。 + config.externals = nodeExternals({ + // 不要外置化 webpack 需要处理的依赖模块。 + // 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件, + // 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单 + whitelist: /\.(css|sass)$/ + }); + + // 这是将服务器的整个输出 + // 构建为单个 JSON 文件的插件。 + // 默认文件名为 `vue-ssr-server-bundle.json` + config.plugins.push(new VueSSRServerPlugin()); + break; + } + default: { + // serve模式 + console.log("serve模式"); + + // config.resolve.symlinks(true); + config.devServer = {}; + + // 两种配置都可以 + config.entry = "./src/entry-client.js"; + // config.entry = { + // app: ["./src/entry-client.js"] + // }; + break; + } + } + + if (process.env.NODE_ENV === "production") { + // 为生产环境修改配置... + } else { + // 为开发环境修改配置... + } + }, + // https://cli.vuejs.org/zh/config/#chainwebpack + chainWebpack: config => { + // 配置html-webpack-plugin + config.plugin("html").tap(args => { + // inject为true会自动在html文件中添加js和css引用 + args[0].inject = true; + args[0].template = "./public/index.html"; + args[0].favicon = "./public/favicon.ico"; + args[0].title = pkg.name.concat(" v").concat(pkg.version); + args[0].ssrEnv = process.env.SSR_ENV; + args[0].debug = process.env.VUE_APP_DEBUG; + args[0].minify = { + //压缩HTML文件 + removeComments: false, //保留HTML中的注释 + collapseWhitespace: process.env.NODE_ENV === "production" //删除空白符与换行符 + }; + return args; + }); + } +};