Эх сурвалжийг харах

feat: 支持留资表单限制需求

zhangyuhan 6 сар өмнө
parent
commit
d2a8020189

+ 5 - 4
client/pages/editor/DataModel.js

@@ -140,8 +140,9 @@ let pageConfig = {
   // 项目配置信息字段
   // 项目配置信息字段
 let projectConfig = {
 let projectConfig = {
   name: '',
   name: '',
-  title: '未命名场景',
-  description: '我用可视化编辑器做了一个超酷炫的H5,快来看看吧。',
+  title: '剑鱼标讯',
+  description: '剑鱼标讯是国内专业的招标大数据服务平台,专注于全国招标采购信息的搜索查询、订阅推送和数据定制化服务。',
+  keywords: '招标网站,招标信息查询,剑鱼标讯,招标采购信息,招标大数据平台',
   coverImage: '',
   coverImage: '',
   author: '',
   author: '',
   script: '',
   script: '',
@@ -151,8 +152,8 @@ let projectConfig = {
   shareConfig: {
   shareConfig: {
     "shareWx": false,
     "shareWx": false,
     "coverImage": "",
     "coverImage": "",
-    "title": "这是#分享者#的大力推荐",
-    "description": "这是#分享者#大力推荐的H5"
+    "title": "剑鱼标讯",
+    "description": "剑鱼标讯是国内专业的招标大数据服务平台,专注于全国招标采购信息的搜索查询、订阅推送和数据定制化服务。"
   },
   },
 }
 }
 
 

+ 69 - 0
client/pages/editor/components/attr-configure/attr-props-components/props-attr/SourceForm.vue

@@ -37,6 +37,66 @@
                 @change="changeOptions">
                 @change="changeOptions">
             </el-input>
             </el-input>
           </el-form-item>
           </el-form-item>
+
+          <el-form-item label="提交次数限制">
+            <el-radio-group v-model="temp.submitCountState">
+              <el-radio :label="-1">无限制</el-radio>
+              <el-radio :label="1">仅限提交一次</el-radio>
+            </el-radio-group>
+            <el-input
+                v-show="temp.submitCountState === 1"
+                placeholder="请输入限制后提示文字"
+                v-model.trim="temp.submitCountMaxTip">
+            </el-input>
+          </el-form-item>
+
+          <el-form-item label="提交时间限制">
+            <el-radio-group v-model="temp.submitTimeState">
+              <el-radio :label="-1">无限制</el-radio>
+              <el-radio :label="1">特定时间</el-radio>
+            </el-radio-group>
+            <el-date-picker
+                v-show="temp.submitTimeState === 1"
+                v-model="temp.submitTime"
+                :picker-options="pickerOptions"
+                type="datetimerange"
+                value-format="timestamp"
+                range-separator="至"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期">
+            </el-date-picker>
+            <el-input
+                v-show="temp.submitTimeState === 1"
+                placeholder="请输入未开始提示文字"
+                v-model.trim="temp.submitTimeBeforeTip">
+            </el-input>
+            <el-input
+                v-show="temp.submitTimeState === 1"
+                placeholder="请输入已结束提示文字"
+                v-model.trim="temp.submitTimeAfterTip">
+            </el-input>
+          </el-form-item>
+
+          <el-form-item label="提交成功动作">
+            <el-radio-group v-model="temp.submitSuccessState">
+              <el-radio :label="-1">提示文字</el-radio>
+              <el-radio :label="0">提示图片</el-radio>
+              <el-radio :label="1">跳转页面</el-radio>
+            </el-radio-group>
+            <el-input
+                v-show="temp.submitSuccessState === -1"
+                placeholder="请输入提示文字"
+                v-model.trim="temp.submitSuccessTip">
+            </el-input>
+
+            <imageSelect v-show="temp.submitSuccessState === 0" :url.sync="temp.submitSuccessImage" />
+
+            <el-input
+                v-show="temp.submitSuccessState === 1"
+                placeholder="请输入跳转网址"
+                v-model.trim="temp.submitSuccessURL">
+            </el-input>
+          </el-form-item>
         </div>
         </div>
       </div>
       </div>
     </el-collapse-item>
     </el-collapse-item>
@@ -46,8 +106,12 @@
 </template>
 </template>
 
 
 <script>
 <script>
+import imageSelect from '@client/components/image-select'
 	export default {
 	export default {
 		name: "attr-sourceFormConfig",
 		name: "attr-sourceFormConfig",
+    components: {
+      imageSelect
+    },
 		props: {
 		props: {
       sourceFormConfig: {
       sourceFormConfig: {
         type: Object
         type: Object
@@ -56,6 +120,11 @@
 		data() {
 		data() {
 			return {
 			return {
         activeNames: ['1'],
         activeNames: ['1'],
+        pickerOptions: {
+          disabledDate () {
+            return false
+          }
+        },
         temp: {
         temp: {
           source: ''
           source: ''
         },
         },

+ 2 - 2
client/pages/home/components/preview-template.vue

@@ -8,7 +8,7 @@
         </el-form-item>
         </el-form-item>
         <el-form-item label="页面链接:">
         <el-form-item label="页面链接:">
           <div><el-button type="primary" @click="doCopy">复制链接</el-button></div>
           <div><el-button type="primary" @click="doCopy">复制链接</el-button></div>
-          <div class="share-wx-config-wrapper">{{$config.baseURL + '/view/' + pageId}}</div>
+          <div class="share-wx-config-wrapper">{{ pageLink }}</div>
         </el-form-item>
         </el-form-item>
         <!--页面效果-->
         <!--页面效果-->
         <el-form-item label="页面信息:">
         <el-form-item label="页面信息:">
@@ -60,7 +60,7 @@
 		},
 		},
 		computed: {
 		computed: {
 			pageLink(){
 			pageLink(){
-				return this.$config.baseURL + '/view/' + this.pageId
+        return this.$config.baseURL + (this.pageData.isPublish ? '/view/': '/in-preview/') + this.pageId
 			},
 			},
 			shareData(){
 			shareData(){
 				if(!this.pageData.shareConfig){
 				if(!this.pageData.shareConfig){

+ 2 - 2
client/pages/home/components/preview.vue

@@ -9,7 +9,7 @@
         </el-form-item>
         </el-form-item>
         <el-form-item label="页面链接:">
         <el-form-item label="页面链接:">
           <div><el-button type="primary" @click="doCopy">复制链接</el-button></div>
           <div><el-button type="primary" @click="doCopy">复制链接</el-button></div>
-          <a class="share-wx-config-wrapper" target="_blank" :href="$config.baseURL + '/view/' + pageId">{{$config.baseURL + '/view/' + pageId}}</a>
+          <a class="share-wx-config-wrapper" target="_blank" :href="pageLink">{{pageLink}}</a>
         </el-form-item>
         </el-form-item>
         <!--页面效果-->
         <!--页面效果-->
         <el-form-item label="页面状态:">
         <el-form-item label="页面状态:">
@@ -62,7 +62,7 @@
     },
     },
     computed: {
     computed: {
 			pageLink(){
 			pageLink(){
-				return this.$config.baseURL + '/view/' + this.pageId
+				return this.$config.baseURL + (this.pageData.isPublish ? '/view/': '/in-preview/') + this.pageId
       },
       },
 			shareData(){
 			shareData(){
 				if(!this.pageData.shareConfig){
 				if(!this.pageData.shareConfig){

+ 204 - 26
client/plugins/SourceForm/src/index.vue

@@ -1,15 +1,26 @@
 <!--test.vue-->
 <!--test.vue-->
 <template>
 <template>
-  <div>
+  <div class="source-form-top-container">
+    <div class="source-form-tip-container" v-if="!canWrite">
+      <div class="source-form-content-container">
+        <van-empty :description="notCanWriteTip" />
+      </div>
+    </div>
+    <van-overlay class="show-success-dialog-container" :show="isShowSuccessDialog" @click="successDialogShow = false">
+      <div @click.stop class="show-success-dialog-content-container">
+        <img v-if="useSourceFormConfig.submitSuccessImage" :src="useSourceFormConfig.submitSuccessImage" />
+        <van-icon class="icon-close-dialog" name="clear" @click="successDialogShow = false" />
+      </div>
+    </van-overlay>
     <van-form
     <van-form
         class="source-form"
         class="source-form"
         @submit="onSubmit"
         @submit="onSubmit"
         :style="{
         :style="{
-        'background-color': sourceFormConfig.background
+        'background-color': useSourceFormConfig.background
       }"
       }"
     >
     >
       <van-field
       <van-field
-          v-if="sourceFormConfig.company"
+          v-if="useSourceFormConfig.company"
           v-model.trim="form.company"
           v-model.trim="form.company"
           required
           required
           name="公司名称"
           name="公司名称"
@@ -17,7 +28,7 @@
           placeholder="请输入准确的公司名称"
           placeholder="请输入准确的公司名称"
       />
       />
       <van-field
       <van-field
-          v-if="sourceFormConfig.name"
+          v-if="useSourceFormConfig.name"
           v-model.trim="form.name"
           v-model.trim="form.name"
           required
           required
           name="姓名"
           name="姓名"
@@ -25,21 +36,21 @@
           placeholder="请输入姓名"
           placeholder="请输入姓名"
       />
       />
       <van-field
       <van-field
-          v-if="sourceFormConfig.phone"
+          v-if="useSourceFormConfig.phone"
           v-model.trim="form.phone"
           v-model.trim="form.phone"
           required
           required
           name="手机号"
           name="手机号"
           label="手机号"
           label="手机号"
           placeholder="请输入准确的手机号"
           placeholder="请输入准确的手机号"
       />
       />
-      <van-field name="radio" required label="你希望获得哪个行业的报告" v-if="sourceFormConfig.source_desc">
+      <van-field name="radio" required label="你希望获得哪个行业的报告" v-if="useSourceFormConfig.source_desc">
         <template #input>
         <template #input>
           <div class="custom-radio-type">
           <div class="custom-radio-type">
             <van-radio-group
             <van-radio-group
                 v-model="form.source_desc"
                 v-model="form.source_desc"
             >
             >
               <van-radio
               <van-radio
-                  v-for="item in sourceFormConfig.sourceOptions"
+                  v-for="item in useSourceFormConfig.sourceOptions"
                   :name="item"
                   :name="item"
                   :key="item"
                   :key="item"
               >
               >
@@ -66,12 +77,41 @@
 </template>
 </template>
 
 
 <script>
 <script>
-import { Form, Field, Button, Radio, RadioGroup, Toast } from 'vant';
+import { Form, Field, Button, Radio, RadioGroup, Toast, Empty, Overlay, Icon} from 'vant';
 import $axios from "@/service/httpServer";
 import $axios from "@/service/httpServer";
 
 
+const DEFAULT_SOURCE_CONFIG = {
+  background: 'transparent',
+  source: 'default-source-h5',
+  name: true,
+  phone: true,
+  company: true,
+  source_desc: true,
+  sourceOptions: [
+    '建筑工程',
+    '信息技术',
+    '弱电安防',
+    '医疗卫生',
+    '服务采购',
+    '其他'
+  ],
+  // 提交限制
+  submitCountState: -1,
+  submitTimeState: -1,
+  submitSuccessState: -1,
+  submitTime: [],
+  submitSuccessTip: '提交成功',
+  submitCountMaxTip: '您已提交该表单',
+  submitTimeBeforeTip: '该表单暂未开始填写',
+  submitTimeAfterTip: '该表单已结束填写',
+}
+
 	export default {
 	export default {
     name: 'DsSourceForm',
     name: 'DsSourceForm',
     components: {
     components: {
+        [Overlay.name]: Overlay,
+        [Empty.name]: Empty,
+        [Icon.name]: Icon,
         [Form.name]: Form,
         [Form.name]: Form,
         [Field.name]: Field,
         [Field.name]: Field,
         [Radio.name]: Radio,
         [Radio.name]: Radio,
@@ -80,6 +120,7 @@ import $axios from "@/service/httpServer";
     },
     },
     data() {
     data() {
       return {
       return {
+        successDialogShow: false,
         form: {
         form: {
           name: '',
           name: '',
           phone: '',
           phone: '',
@@ -108,25 +149,127 @@ import $axios from "@/service/httpServer";
       },
       },
       sourceFormConfig: {
       sourceFormConfig: {
         type:Object,
         type:Object,
-        default: ()=>({
-          background: 'transparent',
-          source: 'default-source-h5',
-          name: true,
-          phone: true,
-          company: true,
-          source_desc: true,
-          sourceOptions: [
-              '建筑工程',
-              '信息技术',
-              '弱电安防',
-              '医疗卫生',
-              '服务采购',
-              '其他'
-          ]
-        })
+        default: () => {
+          return DEFAULT_SOURCE_CONFIG
+        }
       }
       }
 		},
 		},
+    computed: {
+      isShowSuccessDialog () {
+        if (this.useSourceFormConfig.submitSuccessState !== 0) {
+          return false
+        }
+        if (this.isEdit) {
+          return true
+        }
+        return this.successDialogShow
+      },
+      isEdit () {
+        return location.href.indexOf('/#/editor?id') !== -1
+      },
+      useSourceFormConfig () {
+        return Object.assign({}, DEFAULT_SOURCE_CONFIG, this.sourceFormConfig)
+      },
+      canWrite () {
+        let result = true
+        if (this.needCheckWriteCount && this.hasCacheWrite) {
+          result = false
+        }
+        if (!this.canTimeing) {
+          result = false
+        }
+        return result
+      },
+      notCanWriteTip () {
+        // 判断表单填写限制、表单过期限制
+        let tip = ''
+        if (this.needCheckTime) {
+          if (!this.isTimeStart) {
+            tip = this.useSourceFormConfig.submitTimeBeforeTip
+          } else if (this.isTimeEnd) {
+            tip = this.useSourceFormConfig.submitTimeAfterTip
+          }
+        }
+
+        if (this.needCheckWriteCount) {
+          if (this.hasCacheWrite) {
+            tip = this.useSourceFormConfig.submitCountMaxTip
+          }
+        }
+        return tip
+      },
+      needCheckWriteCount () {
+        return this.useSourceFormConfig.submitCountState !== -1
+      },
+      needCheckTime () {
+        return this.useSourceFormConfig.submitTimeState !== -1
+      },
+      canTimeing () {
+        if (!this.needCheckTime) {
+          return true
+        }
+        return this.isTimeStart && !this.isTimeEnd
+      },
+      hasCacheWrite () {
+        if (this.isEdit) {
+          return true
+        }
+        let result = false
+        try {
+          result = localStorage.getItem(window._pageData._id) === '1'
+        } catch (e) {
+          console.warn(e)
+        }
+        return result
+      },
+      isTimeStart () {
+        if (this.sourceFormConfig.submitTime[0]) {
+          return Date.now() >= this.sourceFormConfig.submitTime[0]
+        } else {
+          return true
+        }
+      },
+      isTimeEnd () {
+        if (this.sourceFormConfig.submitTime[1]) {
+          return Date.now() >= this.sourceFormConfig.submitTime[1]
+        } else {
+          return false
+        }
+      },
+    },
     methods: {
     methods: {
+      saveCache () {
+        try {
+          localStorage.setItem(window._pageData._id, '1')
+        } catch (e) {
+          console.warn(e)
+        }
+      },
+      submitSuccessCallback () {
+        this.saveCache()
+        switch (this.useSourceFormConfig.submitSuccessState) {
+          case -1: {
+            Toast(this.useSourceFormConfig.submitSuccessTip)
+            break
+          }
+          case 0: {
+            if (this.useSourceFormConfig.submitSuccessImage) {
+              this.successDialogShow = true
+            } else {
+              Toast(this.useSourceFormConfig.submitSuccessTip)
+            }
+            break
+          }
+          case 1: {
+            if (this.useSourceFormConfig.submitSuccessURL) {
+              location.href = this.useSourceFormConfig.submitSuccessURL
+            } else {
+              Toast(this.useSourceFormConfig.submitSuccessTip)
+            }
+            break
+          }
+        }
+      },
       onSubmit (values) {
       onSubmit (values) {
         console.log(values)
         console.log(values)
         Toast.loading({
         Toast.loading({
@@ -134,7 +277,7 @@ import $axios from "@/service/httpServer";
           forbidClick: true
           forbidClick: true
         });
         });
         const params = Object.assign({
         const params = Object.assign({
-          source: this.sourceFormConfig.source,
+          source: this.useSourceFormConfig.source,
           origin: location.href
           origin: location.href
         }, this.form, {
         }, this.form, {
           source_desc: this.form.source_desc === '其他' ? this.form.source_desc_temp : this.form.source_desc
           source_desc: this.form.source_desc === '其他' ? this.form.source_desc_temp : this.form.source_desc
@@ -149,7 +292,7 @@ import $axios from "@/service/httpServer";
           console.log('res', res)
           console.log('res', res)
           Toast.clear()
           Toast.clear()
           if (res.data) {
           if (res.data) {
-            Toast('提交成功')
+            this.submitSuccessCallback()
           } else {
           } else {
             Toast(res.error_msg || '太火爆了,请稍后重试')
             Toast(res.error_msg || '太火爆了,请稍后重试')
           }
           }
@@ -196,4 +339,39 @@ import $axios from "@/service/httpServer";
     }
     }
   }
   }
 }
 }
+.source-form-top-container {
+  position: relative;
+}
+
+.show-success-dialog-container {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.show-success-dialog-content-container {
+  max-width: 80%;
+  img {
+    border-radius: 12px;
+  }
+}
+
+.icon-close-dialog {
+  color: #fff;
+  font-size: 24px;
+}
+.source-form-tip-container {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1;
+  .source-form-content-container {
+    background-color: #fff;
+  }
+}
 </style>
 </style>

+ 3 - 2
service/config/index.js

@@ -1,8 +1,9 @@
 module.exports = {
 module.exports = {
   port: 3333,
   port: 3333,
   mongodb: {
   mongodb: {
-    // url: 'mongodb://192.168.3.206:27080/zyh',
-    url: 'mongodb://172.17.4.251:27080/h5_editor',
+    url: 'mongodb://192.168.3.206:27080/zyh',
+    // url: 'mongodb://172.17.4.251:27080/h5_editor',
+    // url: 'mongodb://127.0.0.1:27080/h5_editor',
     options: {}
     options: {}
   },
   },
   middleware: ['handlerError'],
   middleware: ['handlerError'],

+ 2 - 1
service/core/index.js

@@ -4,6 +4,7 @@
 const path = require('path')
 const path = require('path')
 const Koa = require('koa');
 const Koa = require('koa');
 const { initConfig, initController, initService, initModel, initRouter, initMiddleware, initExtend, initSchedule } = require('./loader');
 const { initConfig, initController, initService, initModel, initRouter, initMiddleware, initExtend, initSchedule } = require('./loader');
+const views = require("koa-views");
 class Application {
 class Application {
   constructor() {
   constructor() {
     this.$app = new Koa();
     this.$app = new Koa();
@@ -72,4 +73,4 @@ class Application {
   }
   }
 }
 }
 
 
-module.exports = Application;
+module.exports = Application;

+ 2 - 1
service/router.js

@@ -20,6 +20,7 @@ module.exports = app => {
   router.get('/page/detail', $middleware.auth, $controller.page.pageDetail);
   router.get('/page/detail', $middleware.auth, $controller.page.pageDetail);
   // 页面渲染
   // 页面渲染
   router.get('/view/:_id', $controller.page.view);
   router.get('/view/:_id', $controller.page.view);
+  router.get('/in-preview/:_id', $controller.page.view);
 
 
   // 页面数据下载
   // 页面数据下载
   router.get('/tool/jsonload', $controller.page.jsonDownload)
   router.get('/tool/jsonload', $controller.page.jsonDownload)
@@ -58,4 +59,4 @@ module.exports = app => {
 
 
 
 
   return router
   return router
-};
+};