Răsfoiți Sursa

新增文章功能增加, 搜索函数更新

kindring 2 ani în urmă
părinte
comite
bca07ceb08

+ 3 - 0
.babelrc

@@ -0,0 +1,3 @@
+{
+  "presets": ["es2015"]
+}

+ 2 - 2
components/solutionList.vue

@@ -7,8 +7,8 @@
          @click="clickSolutionHandle(item)"
       >
           <span class="imgBox">
-             <img :src="'/public/'+item.image" :alt="item.name" class="img">
-
+<!--            判断 字符的第一位是否为 / -->
+             <img :src=" item.image?item.image.charAt(0) == '/'? item.image : '/public/'+item.image : '/public/' " :alt="item.name" class="img">
           </span>
         <span class="more">
               {{lang===langType.cn?"了解更多":getAbbrText("了解更多")}}

+ 4 - 18
nuxt.config.js

@@ -187,7 +187,8 @@ export default {
     // 加入axios 插件
     plugins: [
       "@plugins/svg-icon.js",
-      { src: "@plugins/ckeditor.js", mode: "client" ,ssr: false}
+      { src: "@plugins/ckeditor.js", mode: "client" ,ssr: false},
+
       // {src: '~/plugins/vue-pdf.js', ssr: false}
     ],
     // api中间件
@@ -209,27 +210,12 @@ export default {
 
     // Build Configuration (https://go.nuxtjs.dev/config-build)
     build: {
-
       extractCSS: true,
       extend(config, ctx) {
         loadSvgConfig(config,ctx);
         // 合并js文件
-        // config.optimization.splitChunks = {
-        //   chunks: 'all',
-        //   minChunks: 1,
-        //   cacheGroups: {
-        //     vendor: {
-        //       test: /[\\/]node_modules[\\/]/,
-        //       name(module) {
-        //         // get the name. E.g. node_modules/packageName/not/this/part.js
-        //         // or node_modules/packageName
-        //         const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
-        //         // npm package names are URL-safe, but some servers don't like @ symbols
-        //         return `npm.${packageName.replace('@', '')}`;
-        //       }
-        //     }
-        //   }
-        // }
+        // js文件转为es5
+
       },
     },
     env : process.env.NODE_ENV === 'production' ? env.pro : env.dev,

+ 4 - 2
package.json

@@ -3,9 +3,9 @@
   "version": "1.0.0",
   "private": true,
   "scripts": {
-    "dev": "nuxt --NODE_ENV=development",
+    "dev": "nuxt --NODE_ENV=development --exec babel-node",
     "build": "nuxt build --NODE_ENV=production && node ./buildTools/build.js",
-    "start": "nuxt start --PORT=production ",
+    "start": "nuxt start --PORT=production --exec babel-node",
     "generate": "nuxt generate"
   },
   "dependencies": {
@@ -20,6 +20,7 @@
     "express": "^4.17.1",
     "express-session": "^1.17.3",
     "formidable": "^3.5.0",
+    "kind-form-verify": "git+http://kindring.cn:9123/kindring/FormData.git",
     "log4js": "^6.9.1",
     "mysql2": "^3.4.3",
     "nuxt": "^2.16.3",
@@ -28,6 +29,7 @@
   },
   "devDependencies": {
     "@nuxtjs/tailwindcss": "^5.0.0",
+    "babel-polyfill": "^6.26.0",
     "svg-sprite-loader": "^6.0.11"
   }
 }

+ 35 - 16
pages/manger/news/add.vue

@@ -16,8 +16,10 @@ import {handle} from "../../../until/handle";
 import {apiMap} from "../../../map/apiMap";
 import {rCode} from "../../../map/rcodeMap_esm";
 
+import {fieldCheck} from "../../../until/form/fieldVerify";
 
-
+import {FormVerify} from "kind-form-verify";
+import {escapeHtml, unescapeHtml} from "@/until/unescapeHtml";
 let ClassicEditor;
 // let MyCustomPlugin;
 if (process.client) {
@@ -27,7 +29,7 @@ if (process.client) {
   // MyCustomPlugin = require('../../../until/customCkeditorPlugin');
 }
 
-
+let formVerify = null;
 export default {
   name: "add",
   components: {
@@ -66,6 +68,21 @@ export default {
       return arr;
     },
   },
+  mounted() {
+    formVerify = new FormVerify(
+      this.form,
+      fieldCheck,
+    )
+    // fieldCheck.checkField('type',this.form.type.val)
+    // formVerify.checkForm(this.form, true);
+    console.log(formVerify);
+    formVerify.onLog = (msg) => {
+      console.log(msg);
+    };
+  },
+  beforeDestroy() {
+    formVerify = null;
+  },
   data(){
     return {
       editor: ClassicEditor,
@@ -102,6 +119,7 @@ export default {
           val: '',
           init: '',
           msg: '',
+          reCheckField: 'id',
           state: 0
         },
         author: {
@@ -120,7 +138,7 @@ export default {
           val: '',
           init: '',
           msg: '',
-          reCheckField: 'url',
+          reCheckField: 'fileData',
           state: 0
         },
         remark: {
@@ -140,8 +158,6 @@ export default {
     };
     this.initForm();
 
-  },
-  mounted() {
   },
   methods:{
     initForm(){
@@ -187,22 +203,25 @@ export default {
     async onSubmitHandle(){
       // 提交文章
       console.log('提交文章');
-      console.log(this.editorData);
-      let formData = {};
-      let isPass = checkFormItem(this.form);
+      // console.log(this.editorData);
+      // console.log(this.form);
+      let isPass = formVerify.checkForm(this.form, true);
       if(!isPass){
         console.log(this.form);
         return console.log('数据验证不通过');
       }
-      formData.content = this.editorData;
-      formData.type = this.form.type.val;
-      formData.title = this.form.title.val;
-      formData.author = this.form.author.val;
-      formData.source = this.form.source.val;
-      formData.cover = this.form.cover.val;
-      formData.remark = this.form.remark.val;
-      formData.pType = this.form.pType.val;
+
+
+
+      let formData = formVerify.getFormData();
+      console.log('------');
+      console.log(formData);
+      console.log('------');
+      // 将content的内容转换为安全字符
+
+      formData.content = escapeHtml(this.editorData);
       console.log(formData);
+      console.log(unescapeHtml(formData.content));
       // 发送请求至后台
       let [err,res] = await handle(this.$axios.post(
         apiMap.newsAdd.path,

+ 7 - 2
pages/manger/news/index.vue

@@ -29,7 +29,7 @@ const newsColumns = [
   },
   {
     title: "文章封面",
-    dataIndex: 'coverPath',
+    dataIndex: 'image',
     width: '20%',
     scopedSlots: {customRender: 'image'},
   },
@@ -38,6 +38,11 @@ const newsColumns = [
     dataIndex: 'source',
     width: '10%',
   },
+  {
+    title: "创建时间",
+    dataIndex: 'source',
+    width: '10%',
+  },
   {
     title: "操作",
     scopedSlots: {customRender: 'operation'},
@@ -303,7 +308,7 @@ export default {
           </template>
 
           <template slot="image" slot-scope="text,record">
-            <image-viewer :src="text" :alt="record.name" />
+            <image-viewer :src="text?text.charAt(0) == '/'? text : '/public/'+text : '' " :alt="record.name" />
           </template>
 
           <template slot="keyLight" class="flex" slot-scope="text">

+ 1 - 0
plugins/babel-polyfill.js

@@ -0,0 +1 @@
+import 'babel-polyfill'

+ 1 - 1
server/control/c_base.js

@@ -251,7 +251,7 @@ async function searchFiles(type = 0, key, l, p){
     _params.type = type;
   }
   // console.log(_params);
-  [err,res] = await searchHandle('搜索文件失败', d_base.loadFiles, _params, l, p);
+  [err,res] = await searchHandle('搜索文件失败', d_base.loadFiles, _params, null, l, p);
   if(err){
     log.info(`[文件资源] 加载失败 ${err.eDetail||err.message}`)
     return [err,null];

+ 35 - 1
server/control/c_news.js

@@ -32,12 +32,46 @@ async function searchNewsByMini(type, key, p, l){
     '搜索文章失败',
     d_news.searchAllNewsMini,
     _params,
+    null,
     p,
     l,
   );
 }
 
+
+async function addArticle(article){
+  let res;
+  // 获取文章类型
+  let [err, typeRes] = await handle(d_news.getTypeByKey(article.type));
+  if(err){
+    log.error(err);
+    log.error(`[新增文章] 获取文章类型失败 ${err.message}`);
+    return [{
+      code: codeMap.ServerError,
+      message: `文章类型校验失败`
+    }, null];
+  }
+  if(typeRes.length === 0){
+    log.error(`[新增文章] 文章类型不存在`);
+    return [{
+      code: codeMap.NotFound,
+      message: `文章类型不存在`
+    }, null];
+  }
+  let typeItem = typeRes[0];
+  [err, res] = await handle(d_news.addArticle(article, typeItem.type_id));
+  if(err){
+    log.error(`[新增文章] 新增文章失败 ${err.message}`);
+    return [{
+      code: codeMap.ServerError,
+      message: `服务器错误,新增文章失败`
+    }, null];
+  }
+  return [null, res];
+}
+
 module.exports = {
   addReadNum,
-  searchNewsByMini
+  searchNewsByMini,
+  addArticle
 }

+ 7 - 1
server/control/c_solution.js

@@ -66,6 +66,7 @@ async function searchSolution(type, key, p, l)
     '搜索产品失败',
     d_solution.searchSolution,
     _params,
+    null,
     p,
     l,
     (item)=>{
@@ -79,7 +80,7 @@ async function searchSolution(type, key, p, l)
     });
 }
 
-async function searchNews(type, key, p, l)
+async function searchNews(type, key, sortKey, sortType, p, l)
 {
   p = p || 1;
   l = l || 10;
@@ -98,6 +99,10 @@ async function searchNews(type, key, p, l)
     '搜索新闻失败',
     d_solution.searchSolution,
     _params,
+    {
+      key: sortKey,
+      type: sortType
+    },
     p,
     l,
     (item)=>{
@@ -140,6 +145,7 @@ async function searchAllNews(pType,type, key, p, l){
     '搜索文章失败',
     d_solution.searchSolution,
     _params,
+    null,
     p,
     l,
     (item)=>{

+ 1 - 0
server/control/c_user.js

@@ -63,6 +63,7 @@ async function loadAccount(accountId,p, l){
     '加载账号失败',
     d_user.loadAccounts,
     _params,
+    null,
     p,
     l);
 }

+ 2 - 0
server/control/product.js

@@ -64,6 +64,7 @@ async function searchProduct(type, key, p, l)
     '搜索产品失败',
    d_product.searchProducts,
     _params,
+    null,
     p,
     l);
 }
@@ -84,6 +85,7 @@ async function searchProductByMini(type, key, p, l){
     '搜索产品失败',
     d_product.searchProductsByMini,
     _params,
+    null,
     p,
     l);
 }

+ 2 - 1
server/database/d_base.js

@@ -105,11 +105,12 @@ function uploadFiles(type,fileNameArr,uploadTime){
  * 搜索文件数据
  * @param type
  * @param _params
+ * @param sort
  * @param p
  * @param l
  * @returns {*}
  */
-function loadFiles(type = 'array',_params,p,l){
+function loadFiles(type = 'array',_params,sort,p,l){
   let sql = ``;
   let values = [];
   if(isEmpty(_params)){

+ 24 - 2
server/database/d_news.js

@@ -1,5 +1,6 @@
 const mysql = require('./mysql');
 const {searchSql,limitSql} = require("../tools/searchSql");
+const {getUnixTimeStamp} = require("../tools/time_cjs");
 const log = require("../logger").logger("d_news","info");
 
 function addReadNum(id){
@@ -13,8 +14,13 @@ function loadTypes() {
   return mysql.pq(sql, []);
 }
 
+function getTypeByKey(key){
+  let sql = `SELECT * FROM hfy_news_type WHERE type_key = ? limit 1`;
+  return mysql.pq(sql,[key]);
+}
+
 // 轻量搜索接口
-function searchAllNewsMini(type='array',searchParam,page,limit){
+function searchAllNewsMini(type='array',searchParam,sort,page,limit){
   let sql;
   let values = [];
   if(type === 'count'){
@@ -47,9 +53,25 @@ function getNewsById(id){
   return mysql.pq(sql,[id]);
 }
 
+function addArticle(article, typeId){
+  let sql = `INSERT INTO hfy_news (title, remark, author, content, type_id, image, date_time) VALUES (?, ?, ?, ?, ?, ?, ?)`;
+  let values = [];
+  values.push(article.title);
+  values.push(article.remark);
+  values.push(article.author);
+  values.push(article.content);
+  values.push(typeId);
+  values.push(article.cover);
+  values.push(getUnixTimeStamp());
+  log.info(`[新增文章] sql=${sql}, values=${values}`);
+  return mysql.pq(sql,values);
+}
+
 module.exports = {
   addReadNum,
   loadTypes,
   searchAllNewsMini,
-  getNewsById
+  getNewsById,
+  getTypeByKey,
+  addArticle
 }

+ 2 - 2
server/database/d_product.js

@@ -36,7 +36,7 @@ function getProductInfo(id) {
   return mysql.pq(sql, values);
 }
 
-function searchProducts(type='array',searchParam,page,limit){
+function searchProducts(type='array',searchParam,sort,page,limit){
   let sql = ``;
   let values = [];
   if(type === 'count'){
@@ -74,7 +74,7 @@ function searchProducts(type='array',searchParam,page,limit){
  * @param limit
  * @returns {*}
  */
-function searchProductsByMini(type='array',searchParam,page,limit){
+function searchProductsByMini(type='array',searchParam,sort,page,limit){
   let sql = ``;
   let values = [];
   if(type === 'count'){

+ 24 - 1
server/database/d_solution.js

@@ -27,7 +27,7 @@ function loadSolution(key, page, limit) {
   return mysql.pq(sql, values);
 }
 
-function searchSolution(type='array',searchParam,page,limit){
+function searchSolution(type='array', searchParam, sort, page,limit){
   let sql;
   let values = [];
   if(type === 'count'){
@@ -46,6 +46,8 @@ function searchSolution(type='array',searchParam,page,limit){
         news.title as name,
         news.image,
         news.coverId,
+        news.date_time,
+        news.hits,
         f.filePath as coverPath,
         f.fileType as coverType,
         news.source,
@@ -70,6 +72,27 @@ function searchSolution(type='array',searchParam,page,limit){
     sql += ` and n_type.type_key = ?`
     values.push(searchParam.type)
   }
+
+  // 增加排序
+  if(sort && sort.key && sort.type){
+    // key value 转换
+    if(sort.key === 'date_time')
+    if(sort.key === 'hits'){
+      sort.key = 'news.hits';
+    }else{
+        sort.key = 'news.date_time';
+    }
+
+    if(sort.type === 'asc'){
+      sort.type = 'asc';
+    }else{
+      sort.type = 'desc';
+    }
+    sql += ` order by ${sort.key} ${sort.type}`;
+  }else{
+    sql += ` order by news.date_time desc`;
+  }
+
   // console.log(sql);
   // console.log(values);
   return searchSql(mysql.pq,type,sql,values,limit,page);

+ 2 - 1
server/database/d_user.js

@@ -40,11 +40,12 @@ function checkAccount(id){
  * 加载账号
  * @param type array|count
  * @param _params key
+ * @param sort
  * @param p page
  * @param l limit
  * @returns {*}
  */
-function loadAccounts(type='array',_params,p,l){
+function loadAccounts(type='array',_params,sort,p,l){
   let sql = ``;
   let values = [];
   if(isEmpty(_params)){

+ 4 - 0
server/index.js

@@ -4,6 +4,7 @@ const bodyParser = require('body-parser');
 
 const router = require('./router/index');
 const config_path = require('./configs/path');
+const path = require("path");
 const app = express();
 const log = require('./logger').logger('app', 'info');
 
@@ -13,6 +14,9 @@ const log = require('./logger').logger('app', 'info');
 app.use(config_path.baseFiles, express.static(config_path.files));
 app.use(config_path.baseImages, express.static(config_path.images));
 app.use(config_path.baseVideos, express.static(config_path.videos));
+app.use('/public' + config_path.baseFiles, express.static(config_path.files));
+app.use('/public' + config_path.baseImages, express.static(config_path.images));
+app.use('/public' + config_path.baseVideos, express.static(config_path.videos));
 
 app.use(
   session({

+ 6 - 6
server/router/r_news.js

@@ -104,12 +104,12 @@ router.get('/read',async(req,res)=>{
 router.post('/add',async(req,res)=>{
   try{
     let err, result;
-    let {
-      type, pType, title, author,
-      source, cover, remark, content
-    } = req.body;
-
-    [err, result] = await c.addReadNum(id);
+    let body = req.body;
+    if(isEmpty(body) || !body.title || !body.content || !body.type || !body.cover){
+      paramFail(res, "请按照要求填写数据");
+      return;
+    }
+    [err, result] = await c.addArticle(body);
     if(err){ return controlError(res, err, null);}
     success(res, result);
   }catch (e) {

+ 4 - 3
server/tools/searchSql.js

@@ -17,12 +17,13 @@ function limitSql (limit = 20,page = 1){
  * @param errorText
  * @param dbFn
  * @param _params
+ * @param _sort
  * @param page
  * @param limit
- * @param listChangeHandle [function] map中的每一项的处理函数
+ * @param listChangeHandle
  * @returns {Promise<[err,{arr, total: number, limit, page}]>}
  */
-async function searchHandle(errorText,dbFn,_params,page,limit ,
+async function searchHandle(errorText,dbFn,_params,_sort,page,limit ,
                             listChangeHandle = null
 ){
     let err,response,arrPromise,countPromise;
@@ -30,7 +31,7 @@ async function searchHandle(errorText,dbFn,_params,page,limit ,
     page = toNumber(page);
     limit = limit||20;
     page = page||1;
-    arrPromise = dbFn('array',_params,page,limit);
+    arrPromise = dbFn('array', _params, _sort, page, limit);
     if(page <= 1){
         // 添加计数字段
         countPromise = dbFn('count',_params);

+ 4 - 0
server/tools/time_cjs.js

@@ -65,6 +65,10 @@ function timeFormat(time, format) {
   })
 }
 
+/**
+ * 获取当前时间戳
+ * @returns {number}
+ */
 function getUnixTimeStamp(){
   return Math.round(new Date().getTime()/1000);
 }

+ 11 - 0
until/form/fieldVerify.js

@@ -0,0 +1,11 @@
+import {FieldCheck} from "kind-form-verify"
+
+import {paramsRules} from "./rules"
+
+
+export let fieldCheck  = new FieldCheck(paramsRules);
+
+
+export default {
+    fieldCheck
+};

+ 183 - 0
until/form/rules.js

@@ -0,0 +1,183 @@
+import {toString} from "../typeTool";
+
+let requiredRuleItem = {require: true,message:'该项为必填项'}
+let phoneRule = [{
+  type: 'string',
+  length: 11,
+  message: '手机号长度必须是11字符'
+},{
+  regex: /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/,
+  message: '手机号格式不正确'
+}]
+let passwordRule= [{
+  type: 'string',
+  minLength: 6,
+  maxLength: 18,
+  message: '密码长度为6-18'
+}]
+let imeiRule = [{
+  type: 'string',
+  length: 15,
+  message: 'IMEI号长度应该为15位'
+}]
+const ownerRule= [
+  requiredRuleItem,
+  {
+    type: 'string',
+    minLength: 1,
+    maxLength: 16,
+    message: '用户名owner类型或者长度不一致'
+  },
+]
+const captchaRule = [{
+  type: 'string',
+  length: 4,
+  message: '验证码长度为4'
+}]
+const nameRule = [
+  {
+    type: 'string',
+    min: 1,
+    max: 25,
+    message: '名称长度不符合'
+  }
+]
+
+const hrefRule = [
+  {
+    type: 'string',
+    min: 1,
+    max: 500,
+    message: '链接长度不符合'
+  },
+  {
+    type: 'string',
+    // 是否符合url地址,支持域名与ip/^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?$/
+    regex: /(https?|ftp|file|http):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/,
+    message: '链接格式不正确'
+  },
+];
+
+
+const requireIdRule = [
+  requiredRuleItem,
+]
+
+let checkCode = function (val) {
+  let p = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
+  let factor = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ];
+  let parity = [ 1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2 ];
+  let code = val.substring(17);
+  if(p.test(val)) {
+    let sum = 0;
+    for(let i=0;i<17;i++) {
+      sum += val[i]*factor[i];
+    }
+    console.log(typeof parity[sum % 11])
+    console.log(typeof code.toUpperCase())
+    if(toString(parity[sum % 11]) === code.toUpperCase()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+let checkDate = function (val) {
+  var pattern = /^(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)$/;
+  if(pattern.test(val)) {
+    var year = val.substring(0, 4);
+    var month = val.substring(4, 6);
+    var date = val.substring(6, 8);
+    var date2 = new Date(year+"-"+month+"-"+date);
+    if(date2 && date2.getMonth() === (parseInt(month) - 1)) {
+      return true;
+    }
+  }
+  return false;
+}
+let checkProv = function (val) {
+  let pattern = /^[1-9][0-9]/;
+  let provs = {11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙江 ",31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东",41:"河南",42:"湖北 ",43:"湖南",44:"广东",45:"广西",46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏 ",61:"陕西",62:"甘肃",63:"青海",64:"宁夏",65:"新疆",71:"台湾",81:"香港",82:"澳门"};
+  if(pattern.test(val)) {
+    if(provs[val]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+const checkID = function (val) {
+  if(checkCode(val)) {
+    console.log('code')
+    let date = val.substring(6,14);
+    if(checkDate(date)) {
+      if(checkProv(val.substring(0,2))) {
+        console.log('匹配成功')
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+const cardRule = [
+  requiredRuleItem,
+  function(val){
+    return checkID(val)?'':'身份证验证失败';
+  }]
+
+export const paramsRules = [
+  {
+    name: "用户名验证规则",
+    checkFields: ['name','workerName','buildingName','entranceName'],
+    rules: nameRule,
+  },
+  {
+    name: "设备imei号验证",
+    checkFields: ['imei','IMEI','Imei'],
+    rules: imeiRule,
+  },
+  {
+    name: "类型等必填项验证规则",
+    checkFields: ['workerType','type','cameraType','buildingAbout','entranceId'],
+    rules: [requiredRuleItem],
+  },
+  {
+    name: "手机号验证",
+    checkFields: ['phone','workerPhone','companyPhone'],
+    rules: phoneRule,
+  },
+  {
+    name: "验证码验证",
+    checkFields:['captcha','captchaImg'],
+    rules:captchaRule
+  },
+  {
+    name: "账户",
+    checkFields:['owner','account'],
+    rules:ownerRule
+  },
+  {
+    checkFields:['passwd', 'password'],
+    rules:passwordRule
+  },
+  {
+    checkFields: ['card', 'workerCard'],
+    rules: cardRule,
+  },
+  {
+    checkFields: ['href', 'url'],
+    rules: hrefRule,
+  },
+  {
+    checkFields: [/id/gi,'fileData', 'remark'],
+    rules: requireIdRule
+  }
+]
+
+
+export default {
+  paramsRules
+}

+ 0 - 13
until/formFieldCheck/README.md

@@ -1,13 +0,0 @@
-# 表单字段验证
-> 该简易库用于快捷验证字段是否合法
-
-## 安装
-> 跳过,目前暂时引用 `index.js`
-
-## 介绍
-### 使用方法
-1. 创建字段验证规则
-2. 给验证规则绑定对应的字段 array
-3. 创建验证器
-4. 创建验证表单实例,使用 json 对象传入表单值
-5. 使用方法验证表单

+ 0 - 291
until/formFieldCheck/fieldCheck.js

@@ -1,291 +0,0 @@
-/**
- * 表单字段验证库
- * author:kindring
- * date:2023/10/08
- */
-
-/**
- * @typedef {string} errMessage 错误信息
- */
-
-
-/**
- * @typedef { Array<string | RegExp> } checkFields 验证字段匹配项
- */
-/**
- * @typedef {Object} checkRule 规则对象
- * @property {string} [type] 类型
- * @property {number} [min] 最小值
- * @property {number} [max] 最大值
- * @property {number} [length] 长度
- * @property {RegExp} [regex] 正则表达式
- * @property {errMessage} [message] 错误信息
- * @property {boolean} [require] 是否必须
- * @property {number} [minLength] 最小长度
- * @property {number} [maxLength] 最大长度
- * @property {validatorFunction} [validator] 自定义验证函数
- */
-
-/**
- * @typedef {function} validatorFunction 自定义验证函数
- * @param {any} value 需要验证的值
- * @returns {string} 返回错误信息或者 null
- */
-
-/**
- * @typedef {Object} ruleItem 验证规则对象
- * @property {Array<string>} checkFields 需要验证的字段
- * @property {Array<validatorFunction | checkRule>} rules 验证规则
- */
-
-/**
- * @typedef {number} checkCode 验证码
- * @property {1} code_pass 验证通过
- * @property {2} code_notPass 验证不通过
- * @property {3} code_notMatch 未匹配到验证规则
- */
-
-
-/**
- * @class FieldCheck
- * @description 表单字段验证类
- * @property {Array<ruleItem>} ruleItems 验证规则
- * @property {function} addRuleItem 添加一条验证规则
- * @property {function} verify 检查表单是否符合规则
- * @example
- * let fieldCheck = new FieldCheck();
- * fieldCheck.addRuleItem('rule1',['name'],[
- *    {
- *    type: 'string',
- *    minLength: 2,
- *    maxLength: 10,
- *    message: '姓名必须为2-10个字符'
- *    }
- *    ]);
- *    fieldCheck.addRuleItem('rule2',['age'],[
- *    {
- *    type: 'number',
- *    min: 18,
- *    max: 100,
- *    message: '年龄必须为18-100岁'
- *    }]);
- *    let errMsg = fieldCheck.verify({
- *    name: 'kindring',
- *    age: 18});
- *    console.log(errMsg);
- *    // null
- *    let errMsg = fieldCheck.verify({
- *    name: 'kindring',
- *    age: 17});
- *    console.log(errMsg);
- *    // 年龄必须为18-100岁
- */
-class FieldCheck{
-    // 通过
-    #code_pass = 1;
-    // 未通过
-    #code_notPass = 2;
-
-    // 无法匹配到验证规则
-    #code_notMatch = 3;
-
-    /**
-     * @type {Array< ruleItem >}
-     */
-    #ruleItems = [];
-    constructor() {
-        this.#ruleItems = [];
-    }
-
-    /**
-     * 判断值是否定义
-     * @param v
-     * @returns {boolean}
-     * @private
-     */
-    _isDef (v) {
-        return v !== undefined && v !== null
-    }
-    _toString = Object.prototype.toString;
-    /**
-     * 判断是否为空
-     * @param v
-     * @returns {boolean}
-     */
-    _isEmpty(v){
-        return v === undefined || v === '';
-    }
-    _isRegExp (v) {
-        return this._toString.call(v) === '[object RegExp]'
-    }
-
-
-    /**
-     * 构建验证规则
-     * @param {Array<string | RegExp>} checkFields 需要验证的字段
-     * @param {Array<validatorFunction | checkRule>} ruleArr 验证规则
-     * @returns {ruleItem} 验证规则对象
-     */
-    buildRuleItem( checkFields , ruleArr) {
-        //  检测checkFields是否为数组
-        //  检测ruleArr是否为数组
-        if(!Array.isArray(checkFields) || !Array.isArray(ruleArr)){
-            throw new Error('checkFields or ruleArr is not Array');
-        }
-        //  检测checkFields中的每一项是否为字符串或者正则
-        for(let field of checkFields){
-            if(typeof field !== 'string' && !(field instanceof RegExp)){
-                throw new Error('checkFields item is not string or RegExp');
-            }
-        }
-        //  检测ruleArr中的每一项是否为函数或者对象
-        for(let rule of ruleArr){
-            if(typeof rule !== 'function' && typeof rule !== 'object'){
-                throw new Error('ruleArr item is not function or object');
-            }
-        }
-        /**
-         * @type {ruleItem}
-         */
-        let ruleItem = {
-            checkFields: checkFields,
-            rules: ruleArr
-        }
-        // this.ruleItems = this.ruleItems.push(ruleItem);
-        return ruleItem;
-    }
-
-    /**
-     * 添加一条验证规则
-     * @param { string } ruleName 验证规则名,用于区分
-     * @param { Array<string | RegExp> } checkFields 用于匹配字段的字符或者正则数组
-     * @param { Array<validatorFunction | checkRule> } ruleArr 验证规则
-     * @returns { FieldCheck } 返回当前对象
-     */
-    addRuleItem( ruleName, checkFields , ruleArr) {
-        let ruleItem = this.buildRuleItem(checkFields,ruleArr);
-        this.#ruleItems.push(ruleItem);
-        return this;
-    }
-
-    /**
-     * 获取验证规则
-     * @param { string } field 字段名
-     * @returns { ruleItem } 验证规则
-     */
-    getRuleItem(field){
-        let ruleItem = this.#ruleItems.find(item=>{
-            // 判断是否为正则
-            for (const _matchKey of item.checkFields) {
-                // 判断是否为正则
-                if(_matchKey instanceof RegExp){
-                    // console.log(`使用正则进行匹配,${_matchKey.test(key)}`);
-                    if(_matchKey.test(field)){
-                        // console.log(`通过正则匹配规则成功,${_matchKey.test(key)}`);
-                        return true;
-                    }
-                }else{
-                    // console.log(`比较是否全等,${_matchKey} === ${key} ?${_matchKey === key}`);
-                    if(_matchKey === field){
-                        // console.log(`通过字符${_matchKey}匹配成功`);
-                        return true;
-                    };
-                }
-            }
-            return false;
-        });
-        return ruleItem;
-    }
-
-    /**
-     * 检查字段是否符合规则
-     * @param field 字段名
-     * @param value 字段值
-     * @returns {Array<checkCode | errMessage>} 错误码或错误信息
-     */
-    checkField(field, value){
-        let ruleItem = this.getRuleItem(field);
-        if(!ruleItem || !ruleItem.rules){
-            return [this.#code_notMatch];
-        }
-        // 判断值是否为undefined
-        if(value === undefined){
-            return [this.#code_notPass, '字段值为undefined'];
-        }
-        // 开始匹配规则
-        for(let _rule of ruleItem.rules ){
-            // 判断是否有自定义验证函数
-            if(typeof _rule === 'function'){
-                let  _msg = _rule(value);
-                // console.log(_msg)
-                if(_msg){
-                    return [this.#code_notPass,_msg]
-                }
-            }
-
-            // 判断类型
-            if(_rule.type && typeof value !== _rule.type){
-                return [this.#code_notPass, _rule.message]
-            }
-
-            // 判断是否为必填项
-            if(_rule.require && this._isEmpty(value)){
-                return [this.#code_notPass, _rule.message]
-            }
-
-            // 判断最小值
-            if(_rule.min && value < _rule.min){
-                return [this.#code_notPass, _rule.message]
-            }
-
-            // 判断最大值
-            if(_rule.max && value > _rule.max){
-                return [this.#code_notPass, _rule.message]
-            }
-
-            // 判断值是否达到指定长度
-            if(_rule.length && value.length && value.length !== _rule.length){
-                return [this.#code_notPass, _rule.message]
-            }
-
-            // 判断最小长度
-            if(_rule.minLength && value.length && value.length < _rule.minLength){
-                return [this.#code_notPass, _rule.message]
-            }
-
-            // 判断最大长度
-            if(_rule.maxLength && value.length && value.length > _rule.maxLength){
-                return [this.#code_notPass, _rule.message]
-            }
-
-            // 判断是否符合正则
-            if(_rule.regex && !_rule.regex.test(value)){
-                return [this.#code_notPass, _rule.message]
-            }
-
-        }
-
-        return [this.#code_pass]
-
-    }
-
-    /**
-     * 检查表单是否符合规则
-     * @param { Object } formObject 需要检验的表单项 字段:值
-     * @param [isMustMatch] 是否强制要求匹配规则
-     * @returns { errMessage } 错误码或错误信息
-     */
-    verify(formObject, isMustMatch){
-        for (const _oKey in formObject) {
-            let value = formObject[_oKey];
-            let r = this.checkField(_oKey,value);
-            if(r[0] === this.#code_notPass){
-                return r[1]
-            }else if(isMustMatch && r[0] === this.#code_notMatch){
-                return `字段没有对应匹配项`
-            }
-        }
-    }
-}
-
-export default FieldCheck;

+ 0 - 295
until/formFieldCheck/formData.js

@@ -1,295 +0,0 @@
-import FieldCheck from "./fieldCheck";
-import fieldIsAllow from "@/until/fieldIsAllow";
-
-let hasOwnProperty = Object.prototype.hasOwnProperty;
-function hasOwn (obj, key) {
-    return hasOwnProperty.call(obj, key)
-}
-
-/**
- * @typedef {object} formItemData 表单项数据
- * @property {string} [val] 表单项值
- * @property {string} [msg] 表单项错误信息
- * @property {number} [state] 表单项状态 0 通过 1 通过 2 不通过
- * @property {string} [showText] 表单项显示文本,用于在某些
- * @property {string} [label] 表单项显示文本
- * @property {string} [init] 表单项初始值
- * @property {Array} [options] 表单项枚举值
- * @property {string} [depend] 依赖字段, 该项存在将使用依赖字段的option中的checkField字段进行匹配验证规则
- * @property {string} [reCheckField] 该表单项用于匹配规则的字段
- * @property {Array} [disables] 禁用项
- */
-
-
-/**
- * @class FormItem
- * @description 表单项
- * @param {object} object 表单项数据
- * @param {FieldCheck} [fieldCheck] 字段验证对象
- * @param {object} [option] 配置项
- */
-class FormItem {
-    formData;
-    /**
-     * @type {FieldCheck} 字段验证对象
-     */
-    fieldCheck;
-    // 表单状态 默认 0 通过 1 不通过 2
-    formState_default = 0;
-    formState_pass = 1;
-    formState_notPass = 2;
-
-    defaultOption = {
-        isMustMatchRule: false,// 表单字段是否必须匹配到验证规则
-    }
-    option = {};
-    /**
-     *
-     * @param object
-     * @param {FieldCheck} [fieldCheck] 字段验证对象
-     * @param {object} [option] 配置项
-     */
-    constructor(object, fieldCheck, option) {
-        this.fieldCheck = fieldCheck || new FieldCheck();
-        // 合并配置项
-        this.option = Object.assign(this.defaultOption, option);
-        let errMsg;
-        // 拿出其中的每一项来构建对应的表单项
-        for (let key in object) {
-            this[key] = object[key];
-            // 验证表单项是否符合要求,不符合要求则抛出错误
-            errMsg = FormItem.buildFormItem(object, key, object[key], this.fieldCheck, this.option.isMustMatchRule);
-            if (errMsg) {
-                throw new Error(`表单项${key}不符合要求,err:${errMsg}`);
-            }
-        }
-        this.formData = object;
-    }
-    static isObject (obj) {
-        return obj !== null && typeof obj === 'object'
-    }
-
-    /**
-     * 检查表单项是否符合要求
-     * @param { object } object 表单项数据
-     * @param { string } field 字段名
-     * @param { formItemData } formItemData 表单项数据
-     * @param { FieldCheck } fieldCheck 字段验证对象
-     * @param { boolean } isMustMatchRule 表单字段是否必须匹配到验证规则
-     * @returns { string } errMsg 错误信息
-     */
-    static buildFormItem(object, field, formItemData, fieldCheck, isMustMatchRule) {
-        if ( !FormItem.isObject(formItemData) ){
-            return `form item ${field} must be object`;
-        }
-        // 是否需要从验证规则表中查找对应的验证规则
-        let isNeedMatchRule = true;
-
-        // 用于匹配的字段
-        let checkFieldStr = field;
-
-        let disables = formItemData.disables;
-
-        // 设置默认值
-        formItemData.val = formItemData.val || formItemData.init || '';
-        // 设置默认提示词
-        formItemData.msg = formItemData.msg || '';
-        // 设置默认状态
-        formItemData.state = formItemData.state || FormData.formState_default;
-        // 设置默认显示文本
-        formItemData.label = formItemData.label || '';
-
-        // 判断是否有 options 选项有则判断是否有 init 选项,没有则设置第一个为 init
-        if ( formItemData.options  ){
-            if( !formItemData.options.length || !formItemData.options[0] ){
-                return `form item ${field} options must be array and has item`;
-            }
-            if ( !formItemData.init ){
-                formItemData.init = formItemData.options[0].key;
-            }
-
-            // 判断 val 与 init 是否存在于 options 中
-            let hasInit = false;
-            for (let i = 0; i < formItemData.options.length; i++) {
-                let option = formItemData.options[i];
-                if ( option.key === formItemData.init ){
-                    hasInit = true;
-                }
-
-                // 判断该options是否为禁用项
-                if ( disables && disables.indexOf(option.key) !== -1 ){
-                    option.disabled = true;
-                }
-            }
-            if ( !hasInit ){
-                return `form item ${field} init value must be in options`;
-            }
-
-        }
-
-        // 判断是否有 depend 依赖字段 有依赖字段则依据依赖字段中的 option 中的 checkField 字段进行判断
-        if( formItemData.depend && formItemData.reCheckField ){
-            return `form item ${field} has depend and reCheckField, but depend and reCheckField can not exist at the same time`;
-        }
-
-        // 判断是否有 depend 依赖字段 有依赖字段则依据依赖字段中的 option 中的 checkField 字段进行判断
-        if ( formItemData.depend ){
-            // 判断依赖字段是否存在
-            if ( !object[formItemData.depend] ){
-                return `form item ${field} depend field ${formItemData.depend} but the field not exist`;
-            }
-            // 判断依赖字段的 option 是否存在
-            if ( !object[formItemData.depend].options ){
-                return `form item ${field} depend field ${formItemData.depend} has no options`;
-            }
-            // 判断依赖字段的 options 中是否有 checkField 字段
-            let hasCheckField = false;
-            for (let i = 0; i < object[formItemData.depend].options.length; i++) {
-                let option = object[formItemData.depend].options[i];
-                if ( option.checkField ){
-                    hasCheckField = true;
-                    checkFieldStr = option.checkField;
-                    break;
-                }
-            }
-            if ( !hasCheckField ){
-                return `form item ${field} depend field ${formItemData.depend} has no checkField`;
-            }
-
-        }
-
-        // 判断是否有 reCheckField 有则使用该字段的值进行规则验证
-        if ( formItemData.reCheckField ){
-            checkFieldStr = formItemData.reCheckField;
-        }
-
-
-
-        // 判断是否有 rules 规则
-        if(isMustMatchRule){
-            if(fieldCheck.getRuleItem(checkFieldStr)){
-                return `form item ${field} has no rules`;
-            }
-        }
-
-        return '';
-    }
-
-    /**
-     * 初始化表单项数据
-     * @param { formObject } formObject 表单对象
-     */
-    static initFormItemData ( formObject ) {
-        let keys = Object.keys(formObject);
-        for(let i = 0; i < keys.length; i++){
-            let key = keys[i];
-            formObject[key].val = formObject[key].init;
-            formObject[key].msg = '';
-            formObject[key].state = FormData.formState_default;
-            formObject[key].showText = '';
-        }
-    }
-
-
-    /**
-     * 检查表单项是否符合要求
-     * @param {object} form 表单对象
-     * @param isMustMatch 是否必须全部匹配到验证规则
-     * @returns {boolean}
-     */
-    checkForm (form, isMustMatch) {
-        let r = true;
-        let n_checkPass = 0,
-            n_checkTotal = 0;
-        let msg = '';
-        for (const fieldKey in form) {
-            let formItem = form[fieldKey];
-            let depend = form[formItem.depend];
-            let checkField = fieldKey;
-            let tmpInd = -1;
-
-            n_checkTotal++;
-
-            if(formItem.reCheckField){
-                checkField = formItem.reCheckField;
-            }
-
-            // 禁用值判断 array
-            if(formItem.disables){
-                if(formItem.disables.indexOf(formItem.val) !== -1){
-                    formItem.msg = '该项内容不合法';
-                    r = false;
-                }
-            }
-
-            // 枚举值判断
-            if(formItem.options){
-                // 有枚举字段,只判断是否在枚举中
-                // console.log(`检测枚举字段:${checkField},值:${formItem.val}`);
-                tmpInd = formItem.options.findIndex(item=>item.value == formItem.val);
-                if(tmpInd === -1){
-                    console.log(`检测枚举字段:${checkField},值:${formItem.val}不在范围内`);
-                    formItem.msg = '选项不在范围内';
-                    formItem.state = 1;
-                    r = false;
-                }else{
-                    // 判断值是否为禁用项
-                    if(formItem.options[tmpInd].disabled){
-                        formItem.msg = '该选项已经被禁用';
-                        r = false;
-                    }
-                }
-                // 枚举值判断完毕,继续下一个字段
-                n_checkPass++;
-                continue;
-            }
-
-            // 依赖字段判断
-            if(depend){
-                if(depend.options){
-                    // 依赖的对象有枚举类型,检查该枚举类型是否有有检测值
-                    let optionItem = depend.options.find(item=>item.value == depend.val);
-                    if(!optionItem){
-                        depend.msg = '选项不在范围内';
-                        formItem.msg = '该值依赖项输入异常';
-                        r = false;
-                        // continue;
-                    }
-                    if(optionItem.checkField){
-                        // console.log(`采用依赖项的检测字段${optionItem.checkField}`)
-                        checkField = optionItem.checkField;
-                    }
-
-                }else{
-                    r = false;
-                }
-                if(!r)
-                {
-                    depend.msg = '该项依赖项输入异常';
-                    formItem.msg = '该值依赖项输入异常';
-                }
-            }
-
-            // 使用验证规则进行
-            formItem.msg = this.fieldCheck.verify({
-                [checkField]:formItem.val,
-            })
-
-
-            if (formItem.msg) r = false;
-            if(r){
-                n_checkPass++;
-                formItem.state = this.formState_pass
-            }else{
-                formItem.state = this.formState_notPass
-            }
-        }
-
-        msg = `检查表单项通过率:${n_checkPass}/${n_checkTotal}`;
-        console.log(msg);
-        return r;
-    }
-
-}
-
-export default FormItem;

+ 0 - 2
until/formFieldCheck/index.js

@@ -1,2 +0,0 @@
-import FieldCheck from "./fieldCheck";
-import FormItem from "./formData";

+ 21 - 0
until/unescapeHtml.js

@@ -9,6 +9,11 @@ export function unescape(html) {
     .replace(/&amp;/g,"")
 }
 
+/**
+ * 反转义html
+ * @param html
+ * @returns {*}
+ */
 export function unescapeHtml(html) {
   return html
     .replace(html ? /&(?!#?\w+;)/g : /&/g, '')
@@ -19,3 +24,19 @@ export function unescapeHtml(html) {
     .replace(/nbsp;/g,"\u00a0")
     .replace(/&amp;/g,"")
 }
+
+
+/**
+ * 转义html
+ * @param html
+ * @returns {*}
+ */
+export function escapeHtml(html) {
+  return html
+    .replace(/&/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/"/g, '&quot;')
+    .replace(/'/g, "&#39;")
+    .replace(/>/g, '&gt;')
+    .replace(/\u00a0/g,"nbsp;")
+}

Fișier diff suprimat deoarece este prea mare
+ 309 - 309
yarn.lock


Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff