xll 2 dagen geleden
bovenliggende
commit
3cf26141d0

+ 2 - 1
app.json

@@ -38,7 +38,8 @@
         "pages/my/merchant/merchant-home/my-users/index",
         "pages/my/my-order/order-detail-good/index",
         "pages/my/my-order/my-refund/refund-good/index",
-        "pages/my/merchant/good/good-edit/index"
+        "pages/my/merchant/good/good-edit/index",
+        "pages/my/merchant/good/good-list/index"
       ]
     },
     {

+ 689 - 2
nova-tourism/components/dev-route/index.js

@@ -1,24 +1,711 @@
 // nova-tourism/components/dev-route/index.js
+let Parse = getApp().Parse;
+const company = getApp().globalData.company
+const uid = Parse.User.current()?.id
+const req = require('../../../utils/request')
 Component({
 
   /**
    * 组件的属性列表
    */
   properties: {
-
+    rid: null, //devRouter的id
+    object_id: null, //编辑的objcetId
+    edit_field_map: null, //字段编辑对象
+    is_btn: null, //是否显示提交按钮(save当前对象)
   },
 
   /**
    * 组件的初始数据
    */
   data: {
-
+    color: '#46a9a4', //主题色
+    text_color: 'black', //文字颜色
+    editMap: {},
+    editFields: [], //编辑对象列表
+    isShowPointer: false, //指针弹框
+    pointerList: [], //指针列表
+    pointer_val: null, //搜索指针的关键字
+    fieldIndex: null, //当前操作的编辑对象index
+    timeout: null, //指针搜索框计时器
+    is_btn: null, //是否显示提交按钮(save当前对象)
+    queryParamsData: null, //当前编辑的对象(不存在则 new)
   },
 
+  lifetimes: {
+    detached: function () {},
+    attached: async function () {
+      this.getToken()
+      setTimeout(() => {
+        this.refersh()
+      }, 800);
+    },
+  },
   /**
    * 组件的方法列表
    */
   methods: {
+    async refersh() {
+      let {
+        is_btn
+      } = this.properties
+      this.setData({
+        is_btn
+      })
+      await this.getDevRoute()
+      this.getDataItem()
+    },
+    /**获取devRoute */
+    async getDevRoute() {
+      let {
+        rid,
+        edit_field_map
+      } = this.properties
+      console.log(edit_field_map)
+
+      let query = new Parse.Query('DevRoute')
+      let d = await query.get(rid)
+      let devRoute = d?.toJSON()
+      console.log(devRoute)
+      let editMap = {}
+      let editFieldsList = []
+      for (let i in devRoute?.editFields) {
+        let item = devRoute?.editFields[i]
+        if (item.key in edit_field_map) { //如果当前字段存在于父组件传递的默认编辑字段之内
+          if (('isHide' in edit_field_map[item.key]) && edit_field_map[item.key]['isHide']) {} else { //排除isHide为true的字段,其他字段使用父组件默认编辑
+            for (let map_key in edit_field_map[item.key]) {
+              devRoute.editFields[i][map_key] = edit_field_map[item.key][map_key]
+            }
+            editFieldsList.push(devRoute.editFields[i])
+            editMap[item.key] = {
+              type: item.type,
+              val: item.default || null
+            }
+          }
+        } else {
+          editFieldsList.push(devRoute.editFields[i])
+          editMap[item.key] = {
+            type: item.type,
+            val: item.default || null
+          }
+        }
+      }
+      console.log(editFieldsList)
+      this.setData({
+        devRoute,
+        className: d?.get('pageUrl')?.split('/')?.pop(),
+        editFields: editFieldsList,
+        editMap
+      })
+    },
+    /**获取数据*/
+    async getDataItem() {
+      let {
+        object_id
+      } = this.properties
+      if (!object_id) return
+      let {
+        className,
+        editMap,
+        editFields
+      } = this.data
+      let pointerKeys = editFields.filter(item => item.type == 'Pointer' || item.view == 'pointer-array')?.map(item => item.key)
+      let query = new Parse.Query(className)
+      for (let i in pointerKeys) {
+        query.include(pointerKeys[i])
+      }
+      let d = await query.get(object_id)
+      if (!d?.id) return
+      let dataItem = d?.toJSON()
+      for (let i in editFields) {
+        let item = editFields[i]
+        if (item.view == 'edit-image') {
+          if (item.type == 'String') { //单张图片
+            editMap[item.key].val = dataItem[item.key] ? [{
+              url: dataItem[item.key]
+            }] : item.default || null
+          }
+          if (item.type == 'Array') { //数组图片
+            if (dataItem[item.key] && dataItem[item.key]?.length > 0) {
+              editMap[item.key].val = dataItem[item.key]?.map(item => {
+                return {
+                  url: item
+                }
+              })
+            } else {
+              editMap[item.key].val = item.default || []
+            }
+
+          }
+        } else {
+          if (item.type == 'Pointer') { //指针类型
+            let text = dataItem[item.key]?.storeName || dataItem[item.key]?.title || dataItem[item.key]?.name || dataItem[item.key]?.orderNum || dataItem[item.key]?.mobile
+            editMap[item.key].text = text
+          } else if (item.type == 'Array' && item.view == 'pointer-array') { //数组指针
+            let text = []
+            for (let x in dataItem[item.key]) {
+              let xtem = dataItem[item.key][x]
+              text.push(xtem?.storeName || xtem?.title || xtem?.name || xtem?.orderNum || xtem?.mobile)
+              editMap[item.key].text = text
+            }
+          }
+          editMap[item.key].val = dataItem[item.key] || item.default || null
+        }
+      }
+      this.setData({
+        dataItem,
+        editMap,
+        queryParamsData: d
+      })
+    },
+    /** 获取token 上传图片所需*/
+    async getToken() {
+      let res = await Parse.Cloud.run('qiniu_uptoken', {
+        company: company
+      })
+      this.setData({
+        uploadURL: res.zoneUrl,
+        domain: res.domain,
+        uptokenURL: res.uptoken,
+      })
+    },
+    /** textarea改变 - String类型*/
+    changeTextarea(e) {
+      let {
+        editMap
+      } = this.data
+      console.log(e)
+      let {
+        key
+      } = e.currentTarget.dataset
+      let {
+        value
+      } = e.detail
+      editMap[key].val = value
+      this.setData({
+        editMap
+      })
+    },
+
+    /**上传单张图片 - String类型 */
+    changeFile(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key
+      } = e.currentTarget.dataset
+      console.log(e.detail[0])
+      editMap[key].val = e.detail
+      this.setData({
+        editMap
+      })
+    },
+    /**单选框改变 - String类型 */
+    radioChange(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key
+      } = e.currentTarget.dataset
+      editMap[key].val = e.detail
+      this.setData({
+        editMap
+      })
+    },
+    /** 数字输入框改变 - Number类型*/
+    changeNumber(e) {
+      let {
+        editMap
+      } = this.data
+      console.log(e)
+      let {
+        key
+      } = e.currentTarget.dataset
+      let {
+        value
+      } = e.detail
+      editMap[key].val = value
+      this.setData({
+        editMap
+      })
+    },
+    /**开关改变 */
+    switchChange(e) {
+      let {
+        editMap
+      } = this.data
+      console.log(e)
+      let {
+        key
+      } = e.currentTarget.dataset
+      editMap[key].val = e.detail
+      this.setData({
+        editMap
+      })
+    },
+    /**上传多张图片 - Array类型 */
+    changeFile_array(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key
+      } = e.currentTarget.dataset
+      editMap[key].val = e.detail
+      this.setData({
+        editMap
+      })
+    },
+    /**添加文本 - Array类型 */
+    addTextarea(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key
+      } = e.currentTarget.dataset
+      editMap[key].val = [...(editMap[key].val || []), e.detail.value]
+      this.setData({
+        editMap
+      })
+    },
+    /**删除文本 - Array类型 */
+    delTextarea(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key,
+        index
+      } = e.currentTarget.dataset
+      editMap[key].val?.splice(index, 1)
+      this.setData({
+        editMap
+      })
+    },
+    /**指针弹框-开 */
+    async openPointer(e) {
+      let {
+        editFields
+      } = this.data
+      let {
+        index
+      } = e.currentTarget.dataset
+      if (editFields[index].disabled) {
+        wx.showToast({
+          title: `无法编辑${editFields[index].name}`,
+          icon: 'none'
+        })
+        return
+      }
+      this.setData({
+        fieldIndex: index,
+        pointerList: [],
+        pointer_val: '',
+        isShowPointer: true
+      })
+      this.getPointerItem()
+    },
+    /**指针弹框-关 */
+    closePointer() {
+      this.setData({
+        isShowPointer: false
+      })
+    },
+    /**选中指针 */
+    checkPointer(e) {
+      let {
+        editFields, //编辑对象列表
+        pointerList, //指针列表
+        fieldIndex, //当前操作的编辑对象index
+        editMap,
+      } = this.data
+      let {
+        index
+      } = e.currentTarget.dataset
+      let editField = editFields[fieldIndex]
+      let p_item = pointerList[index]
+      console.log(pointerList)
+      pointerList = pointerList?.map((item, i) => {
+        if (i == index) {
+          item['dev_router_check'] = true
+        } else {
+          item['dev_router_check'] = false
+        }
+        return item
+      })
+      editMap[editField.key].val = {
+        className: editField?.targetClass,
+        __type: 'Pointer',
+        objectId: p_item?.objectId
+      }
+      editMap[editField.key].text = p_item.storeName || p_item.name || p_item.title || p_item.orderNum || p_item.mobile
+      this.setData({
+        editMap,
+        pointerList
+      })
+      this.closePointer()
+    },
+    /**选中指针 - Array */
+    checkPointer_Array(e) {
+      let {
+        editFields, //编辑对象列表
+        pointerList, //指针列表
+        fieldIndex, //当前操作的编辑对象index
+        editMap,
+      } = this.data
+      let {
+        index
+      } = e.currentTarget.dataset
+      let editField = editFields[fieldIndex]
+      let p_item = pointerList[index]
+      console.log(editField, p_item)
+      pointerList[index]['dev_router_check'] = !(pointerList[index]['dev_router_check'] || false)
+      let checkList = pointerList?.filter(item => item.dev_router_check) || []
+      editMap[editField.key].val = checkList.map(p_item => {
+        return {
+          className: editField?.targetClass,
+          __type: 'Pointer',
+          objectId: p_item?.objectId
+        }
+      })
+      editMap[editField.key].text = checkList.map(p_item => {
+        return p_item.storeName || p_item.name || p_item.title || p_item.orderNum || p_item.mobile
+      })
+      console.log(editMap)
+      this.setData({
+        editMap,
+        pointerList
+      })
+    },
+    /**删除数组指针 */
+    delPointer(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key,
+        index
+      } = e.currentTarget.dataset
+      editMap[key].text?.splice(index, 1)
+      editMap[key].val?.splice(index, 1)
+      this.setData({
+        editMap
+      })
+    },
+    /**指针搜索框变化 */
+    async valChange(e) {
+      await this.setData({
+        pointer_val: e.detail || ''
+      })
+      let {
+        timeout
+      } = this.data
+      clearTimeout(timeout)
+      timeout = setTimeout(async () => {
+        await this.setData({
+          pointerList: [],
+        })
+        this.getPointerItem()
+      }, 1000);
+      this.setData({
+        timeout
+      })
+    },
+    /** 查询指针*/
+    async getPointerItem() {
+      let {
+        editMap,
+        pointer_val,
+        pointerList,
+        fieldIndex,
+        editFields
+      } = this.data
+      let editField = editFields[fieldIndex]
+      let sql = `SELECT DISTINCT(column_name) FROM information_schema.columns
+      WHERE table_name = '${editField.targetClass}'`
+      let columnList = await req.customSQL(sql)
+      let where = {
+        "$or": []
+      }
+      if (editField?.queryParams?.where?.type) {
+        where = JSON.parse(JSON.stringify(editField?.queryParams?.where || {})) || {}
+      } else {
+        where = {}
+      }
+      console.log(where)
+      for (let i in columnList) {
+        let item = columnList[i]
+        if (item.column_name == 'company') where['company'] = {
+          "$eq": company
+        }
+        if (item.column_name == 'isDeleted') where['isDeleted'] = {
+          "$ne": true
+        }
+        if (pointer_val) {
+          if (item.column_name == 'name') where['$or'] = [...(where['$or'] || []), {
+            "name": {
+              "$regex": `${pointer_val}`
+            }
+          }]
+          if (item.column_name == 'title') where['$or'] = [...(where['$or'] || []), {
+            "title": {
+              "$regex": `${pointer_val}`
+            }
+          }]
+          if (item.column_name == 'mobile') where['$or'] = [...(where['$or'] || []), {
+            "mobile": {
+              "$regex": `${pointer_val}`
+            }
+          }]
+          if (item.column_name == 'orderNum') where['$or'] = [...(where['$or'] || []), {
+            "orderNum": {
+              "$regex": `${pointer_val}`
+            }
+          }]
+          if (item.column_name == 'storeName') where['$or'] = [...(where['$or'] || []), {
+            "storeName": {
+              "$regex": `${pointer_val}`
+            }
+          }]
+        }
+      }
+      console.log(where)
+      let queryParams = {
+        where,
+        limit: 20,
+        skip: pointerList?.length || 0
+      }
+      let query = new Parse.Query.fromJSON(editField?.targetClass, queryParams)
+      query.descending('createdAt')
+      let d = await query.find()
+      if (!d?.length) {
+        wx.showToast({
+          title: '没有更多了',
+          icon: 'none'
+        })
+        return
+      }
+      editMap[editField.key].text
+      let list = d?.map(item => {
+        let obj = item.toJSON()
+        if (editMap[editField.key]?.text && editMap[editField.key]?.text?.length > 0) {
+          if (editField.type == 'Array') {
+            let x = editMap[editField.key].val.findIndex(val_item => val_item.objectId == obj.objectId)
+            if (x != -1) {
+              obj.dev_router_check = true
+            }
+          } else {
+            if (editMap[editField.key].val.objectId == obj.objectId) {
+              obj.dev_router_check = true
+            }
+          }
+        }
+        return obj
+      })
+      this.setData({
+        pointerList: [...(pointerList || []), ...(list || [])]
+      })
+    },
+
+    //#region ShopGoods表specMap字段编辑  ================================================
+    /**添加属性 - specMap字段 */
+    addKey_ShopGoods_specMap(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key
+      } = e.currentTarget.dataset
+      let text = e.detail.value
+      let obj = {
+        value: null,
+        price: null,
+        vipPrice: null,
+      }
+      if (!editMap[key].val?.specList || editMap[key].val?.specList?.length <= 0) editMap[key].val = {
+        specList: []
+      }
+      editMap[key].val['specList'] = [...(editMap[key]?.val?.specList || []), text]
+      editMap[key].val[text] = [...(editMap[key]?.val[text] || []), obj]
+      this.setData({
+        editMap
+      })
+    },
+    /**删除属性 - specMap字段 */
+    delKey_ShopGoods_specMap(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key,
+        spec_index
+      } = e.currentTarget.dataset
+      console.log(key, spec_index)
+      let text = editMap[key].val.specList[spec_index]
+      console.log(text)
+
+      delete editMap[key].val[text]
+      editMap[key].val.specList.splice(spec_index, 1)
+      this.setData({
+        editMap
+      })
+    },
+    /**设置specMap-value */
+    setValue(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key,
+        spec,
+        spec_map_index
+      } = e.currentTarget.dataset
+      editMap[key].val[spec][spec_map_index].value = e.detail.value
+      this.setData({
+        editMap
+      })
+    },
+    /**设置specMap-price */
+    setPrice(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key,
+        spec,
+        spec_map_index
+      } = e.currentTarget.dataset
+      editMap[key].val[spec][spec_map_index].price = parseFloat(e.detail.value || 0)
+      this.setData({
+        editMap
+      })
+    },
+    /**设置specMap-vipPrice */
+    setVipPrice(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key,
+        spec,
+        spec_map_index
+      } = e.currentTarget.dataset
+      editMap[key].val[spec][spec_map_index].vipPrice = parseFloat(e.detail.value || 0)
+      this.setData({
+        editMap
+      })
+    },
+    /**添加specMap里面key内的item */
+    addSpecMap(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key,
+        spec
+      } = e.currentTarget.dataset
+      let obj = {
+        value: null,
+        price: null,
+        vipPrice: null,
+      }
+      editMap[key].val[spec] = [...(editMap[key].val[spec] || []), obj]
+      this.setData({
+        editMap
+      })
+    },
+    /**删除specMap里面key内的item */
+    delSpecMapItem(e) {
+      console.log(e)
+      let {
+        editMap
+      } = this.data
+      let {
+        key,
+        spec,
+        spec_map_index
+      } = e.currentTarget.dataset
+      editMap[key].val[spec].splice(spec_map_index, 1)
+      this.setData({
+        editMap
+      })
+    },
+    //#endregion ShopGoods表specMap字段编辑 end ================================================
+
+    /**提交 */
+    async submit() {
+      let {
+        editMap,
+        queryParamsData,
+        className,
+        editFields
+      } = this.data
+      console.log(editMap)
+      let editMapParse = {}
+      if (!queryParamsData?.id) {
+        let NewClass = Parse.Object.extend(className)
+        queryParamsData = new NewClass()
+        queryParamsData.set('company', {
+          className: 'Company',
+          __type: 'Pointer',
+          objectId: company
+        })
+      }
+      for (let i in editFields) {
+        let item = editFields[i]
+
+        if (item.required && ((!editMap[item.key].val) || editMap[item.key].val?.length <= 0)) {
+          wx.showToast({
+            title: `${item.name} 为必填项,请补充`,
+            icon: 'none'
+          })
+          return
+        }
+        if((!editMap[item.key].val) || editMap[item.key].val?.length <= 0) continue
+        if (item.type == 'Number') {
+          editMapParse[item.key] = parseFloat(editMap[item.key].val)
+        } else if (item.type == 'String' && item.view == 'edit-image') {
+          editMapParse[item.key] = editMap[item.key].val[0]?.url
+        } else if (item.type == 'Array') {
+          if (item.view == 'edit-image') {
+            editMapParse[item.key] = editMap[item.key].val?.map(val_item => val_item.url)
+          } else if (item.view == 'pointer-array') {
+            editMapParse[item.key] = editMap[item.key].val?.map(val_item => {
+              return {
+                __type: 'Pointer',
+                className: item.targetClass,
+                objectId: val_item.objectId
+              }
+            })
+          }
+        }
+        queryParamsData.set(item.key, editMapParse[item.key] || editMap[item.key].val)
+      }
+      console.log(editMap)
+      console.log(queryParamsData)
+      await queryParamsData.save()
+      setTimeout(() => {
+        wx.navigateBack({
+          delta: 1
+        })
+      }, 1000);
+     
+    }
 
   }
 })

+ 9 - 1
nova-tourism/components/dev-route/index.json

@@ -1,4 +1,12 @@
 {
   "component": true,
-  "usingComponents": {}
+  "usingComponents": {
+    "van-radio": "@vant/weapp/radio/index",
+    "van-radio-group": "@vant/weapp/radio-group/index",
+    "van-popup": "@vant/weapp/popup/index",
+    "van-tag": "@vant/weapp/tag/index",
+    "van-field": "@vant/weapp/field/index",
+    "van-switch": "@vant/weapp/switch/index",
+    "van-search": "@vant/weapp/search/index"
+  }
 }

+ 160 - 47
nova-tourism/components/dev-route/index.less

@@ -1,60 +1,173 @@
-@import '../../styles/base.less';
-page {
-    // background: #f6f6f6;
-}
-.form {
-    display: flex;
-    flex-wrap: wrap;
-.col-12 {
-    width: 50%;
-}
-}
-.form-item {
-    width: 100%;
-    margin: 20rpx 0;
-    color:#382E2E;
-    .form-label {
-        font-size: 28rpx;
-        margin:20rpx;
-        color: @grey;
-        .required {
-            font-size: 40rpx;
-            vertical-align: middle;
-        }
-    }
-    .form-field {
-        padding: 10rpx;
-        // background: #ffffff;
-        .form-input {
+@name-size: 28rpx;
+@text-size: 26rpx;
+@main-color: #46a9a4;
+@text-color: white;
+
+.item {
+    margin: 20rpx;
+    border-bottom: 1rpx solid whitesmoke;
+    padding-bottom: 20rpx;
+
+    .name {
+        font-size: @name-size;
+        padding-bottom: 10rpx;
+    }
+.content{
+    padding: 0 20rpx;
+    .text {
+        display: flex;
+        align-items: flex-end;
+
+        >textarea {
+            width: 550rpx;
             padding: 10rpx;
-            border: 0.5px solid #eee;
-            border-radius: 10rpx;
+            margin: 5rpx 0;
+            font-size: @text-size;
+            min-height: 100rpx;
+            background: whitesmoke;
+        }
+
+        .btn {
+            margin: 0 10rpx;
+            padding: 5rpx 10rpx;
+            font-size: @text-size;
+            background: @main-color;
+        }
+
+        .title {
+            margin-right: 20rpx;
+            font-size: @text-size;
+        }
+    }
+
+    .radioGroup {
+        .radio {
+            font-size: @text-size;
+            padding: 5rpx;
+        }
+    }
+
+    .tags {
+        margin-bottom: 10rpx;
+
+        van-tag {
+            margin-right: 10rpx;
+        }
+    }
+
+    .btn_Pointer {
+        width: 50vw;
+
+        button {
+            font-size: 26rpx;
+            width: 50vw;
+        }
+    }
+
+    .specMap {
+        .tip {
+            font-size: @text-size;
+            color: red;
         }
-        .form-input-num {
-            width: 200rpx;
+
+        .list {
+            .tags {
+                .title {
+                    font-weight: bold;
+                    font-size: @text-size;
+                }
+            }
+        }
+
+        .obj {
+            .title {
+                margin: 10rpx 0;
+                font-weight: bold;
+                font-size: @text-size;
+            }
+
+            .obj_item {
+                margin: 10rpx;
+                padding: 10rpx;
+                background: whitesmoke;
+
+                .key {
+                    font-weight: bold;
+                    font-size: @text-size;
+                }
+
+                .info {
+                    .info_item {
+                        display: flex;
+                        padding: 10rpx 0;
+                        border-bottom: 1rpx solid white;
+                        position: relative;
+
+                        >view {
+                            margin: 0 3rpx;
+                            >text {
+                                font-size: @text-size;
+                            }
+
+                            >input {
+                                border: 1rpx solid rgb(201, 201, 201);
+                                padding: 10rpx;
+                                font-size: @text-size;
+
+                            }
+                        }
+
+                        .del {
+                            width: 40rpx;
+                            height: 40rpx;
+                            background: rgb(207, 207, 207);
+                            display: flex;
+                            justify-content: center;
+                            position: absolute;
+                            right: 0;
+                            top: 0;
+                        }
+                    }
+                    .btn_specMap{
+                        width: 50%;
+                        >button{
+                            font-size: @text-size;
+                        }
+                    }
+                }
+            }
         }
     }
 }
+ 
+}
 
+.popup {
+    width: 100%;
+    height: 70vh;
 
-.tag-wrapper{
-    display: flex;
-    align-items: center;
-    color:#382E2E;
-    .add-btn {
-        width: auto;
+    .title {
+        font-size: @name-size;
+        height: 90rpx;
+        line-height: 90rpx;
+        text-align: center;
+        border-bottom: 1rpx solid whitesmoke;
     }
-    .tags {
-        flex: 1;
-        display: flex;
-        flex-wrap: wrap;
-        .tag {
-            margin:10rpx;
+
+    .itemBox {
+        overflow-y: auto;
+        height: calc(70vh - 250rpx);
+
+        .item {
+            font-size: @text-size;
+            border-bottom: 1rpx solid whitesmoke;
         }
     }
-    
 }
+
 .footer {
-    margin-bottom: 100rpx;
-    padding: 20rpx;
+    .btn {
+        width: 100vw;
+        border-radius: 0;
+    }
 }

+ 141 - 55
nova-tourism/components/dev-route/index.wxml

@@ -1,60 +1,146 @@
-<view class="page-section form" style="color:#382E2E; ">
-    <block wx:for="{{route['editFields']}}" wx:key="index" wx:for-item="field">
-                <view class="form-item {{field.type == 'Number'?'col-12':''}}" wx:if="{{field.key != ( 'shop' || 'company' ||  'department')}}">
-                    <view class="form-label" >
-                        <text wx:if="{{field.required}}" class="red required">*</text>
-                        <text class="form-label-text">{{field.name}}:</text>
+<view class="item" wx:for="{{editFields}}" wx:key="index">
+  <view class="name"> <text wx:if="{{item.required}}" style="color: red;">*</text> {{item.name}}:</view>
+  <view class="content">
+    <block wx:if="{{className=='ShopGoods'&&item.key=='specMap'}}">
+      <view class="specMap">
+        <view class="tip">不同规格价格不同可在规格属性里面填写价格,价格一样可不填写,编辑完之后需要保存</view>
+        <view class="list">
+          <view class="tags">
+            <text class="title">属性名称:</text>
+            <block wx:for="{{editMap[item.key].val.specList}}" wx:for-item="spec_item" wx:for-index="spec_index" wx:key="spec_item">
+              <van-tag closeable="{{!item.disabled}}" type="primary" size="medium" color="{{color}}" text-color="{{text_color}}" data-key="{{item.key}}" data-spec_index="{{spec_index}}" bind:close="delKey_ShopGoods_specMap">{{spec_item}}</van-tag>
+            </block>
+          </view>
+          <view class="text">
+            <textarea disabled="{{item.disabled}}" confirm-type="点击添加" data-key="{{item.key}}" bindconfirm="addKey_ShopGoods_specMap" placeholder="请输入规格名称(可填多个)" auto-height></textarea>
+          </view>
+        </view>
+        <view class="obj">
+          <view class="title">属性对象:</view>
+          <block wx:for="{{editMap[item.key].val.specList}}" wx:for-item="spec_item" wx:for-index="spec_index" wx:key="spec_item">
+            <view class="obj_item">
+              <view class="key">{{spec_item}}:</view>
+              <view class="info">
+                <block wx:for="{{editMap[item.key].val[spec_item]}}" wx:for-item="spec_map_item" wx:for-index="spec_map_index" wx:key="spec_map_item">
+                  <view class="info_item">
+                    <view>
+                      <text>属性值:</text>
+                      <input disabled="{{item.disabled}}" data-key="{{item.key}}" data-spec="{{spec_item}}" data-spec_map_index="{{spec_map_index}}" bindinput="setValue" value="{{spec_map_item.value}}" placeholder="输入属性值" type="text" />
                     </view>
-                    <view class="form-field">
-                        <block wx:if="{{field.type == 'String'}}">
-                            <block wx:if="{{!field.view}}">
-                                <input class="form-input" border="{{true}}"
-                                value="{{ formData[field.key] }}"
-                                placeholder="请输入{{field.name}}"  data-field="{{field.key}}" data-type="{{field.type}}"
-                                bindinput="onChange"/>
-                            </block>
-                        </block>
-                        <block wx:if="{{field.type == 'Number'}}">
-                            <block wx:if="{{!field.view}}">
-                                <input class="form-input form-input-num" min="0" type="number" border="{{true}}"
-                                value="{{ formData[field.key] }}" 
-                                placeholder="请输入{{field.name}}" data-field="{{field.key}}" data-type="{{field.type}}"
-                                bindinput="onChange"/>
-                            </block>
-                        </block>
-                        <block wx:if="{{field.type == 'Boolean'}}">
-                            <block wx:if="{{!field.view}}">
-                                <van-switch checked="{{ formData[field.key] }}" data-field="{{field.key}}"  data-type="{{field.type}}" active-color="#07c160"  size="24px" bind:change="onChange" />
-                            </block>
-                        </block>
-                        <block wx:if="{{field.type == 'Array'}}">
-                            <block wx:if="{{!field.view}}">
-                                <view class="tag-wrapper">
-                                    <view class="tags">
-                                        <block wx:for="{{formData[field.key]}}" wx:key="index" wx:for-item="tag">
-                                            <van-tag plain size="large" closeable data-field="{{field.key}}" data-index="{{index}}" bind:close="tagClose"  class="tag" type="primary">{{tag}}</van-tag>
-                                        </block>
-                                    </view>
-                                    <van-button plain type="primary" data-field="{{field.key}}" data-name="{{field.name}}"  bindtap="showTagEdit"  class="add-btn">添加{{field.name}}</van-button>
-        
-                                </view>
-                            </block>
-                            <block wx:if="{{field.view == 'edit-filemanager'}}">
-                                <upload data-field="{{field.key}}" bind:onChangeFile="changeFile" fileList="{{ formData[field.key] }}" accept="image" maxCount="9" uploadURL="{{uploadURL}}" domain="{{domain}}" uptokenURL="{{uptokenURL}}"></upload>
-                            </block>
-                        </block>
-                        <block wx:if="{{field.type == 'GeoPoint'}}">
-                            <block wx:if="{{!field.view}}">
-                                <van-button data-field="{{field.key}}" bind:tap="chooseGeoPoint" type="primary" size="small">选择{{field.name}}</van-button>
-                                <view>
-                                    <text class="text-small grey">{{formData['address']}}</text>
-                                </view>
-                            </block>
-                        </block>
+                    <view>
+                      <text>价格:</text>
+                      <input disabled="{{item.disabled}}" data-key="{{item.key}}" data-spec="{{spec_item}}" data-spec_map_index="{{spec_map_index}}" bindinput="setPrice" value="{{spec_map_item.price}}" placeholder="输入价格" type="digit" />
+                    </view>                                                
+                    <view>
+                      <text>会员价格:</text>
+                      <input disabled="{{item.disabled}}" data-key="{{item.key}}" data-spec="{{spec_item}}" data-spec_map_index="{{spec_map_index}}" bindinput="setVipPrice" value="{{spec_map_item.vipPrice}}" placeholder="输入会员价格" type="digit" />
                     </view>
+                    <view wx:if="{{editMap[item.key].val[spec_item].length>1&&!item.disabled}}" class="del" data-key="{{item.key}}" data-spec="{{spec_item}}" data-spec_map_index="{{spec_map_index}}" bind:tap="delSpecMapItem">
+                      <van-icon name="cross" />
+                    </view>
+                  </view>
+                </block>
+                <view wx:if="{{!item.disabled}}" class="btn_specMap" style="border:1rpx solid {{color}};">
+                  <button data-key="{{item.key}}" data-spec="{{spec_item}}" bind:tap="addSpecMap" style="color: {{color}};">
+                    <van-icon name="plus" />添加
+                  </button>
                 </view>
+              </view>
+            </view>
+          </block>
+
+        </view>
+      </view>
+    </block>
+    <block wx:elif="{{item.type=='String'}}">
+      <block wx:if="{{!item.view}}">
+        <view class="text">
+          <textarea value="{{editMap[item.key].val}}" data-key="{{item.key}}" bindblur="changeTextarea" placeholder="请输入{{item.name}}" auto-height disabled="{{item.disabled}}"></textarea>
+        </view>
+      </block>
+      <block wx:elif="{{item.view=='edit-image'}}">
+        <view class="image">
+          <block wx:if="{{item.disabled}}">
+            <image style="width:160rpx;height: 160rpx;" src="{{editMap[item.key].val[0].url}}" mode="" />
+          </block>
+          <block wx:else>
+            <upload fileList="{{editMap[item.key].val}}" accept="all" data-key="{{item.key}}" bind:onChangeFile="changeFile" accept="image" maxCount="1" uploadURL="{{uploadURL}}" domain="{{domain}}" uptokenURL="{{uptokenURL}}"></upload>
+          </block>
+        </view>
+      </block>
+      <block wx:elif="{{item.view=='edit-select'}}">
+        <van-radio-group disabled="{{item.disabled}}" value="{{editMap[item.key].val}}" class="radioGroup" data-key="{{item.key}}" bind:change="radioChange">
+          <view wx:for="{{item.options}}" wx:for-item="option" wx:key="option" class="radio">
+            <van-radio checked-color="{{color}}" name="{{option.value}}">{{option.label}}</van-radio>
+          </view>
+        </van-radio-group>
+      </block>
+    </block>
+    <block wx:elif="{{item.type=='Number'}}">
+      <van-field disabled="{{item.disabled}}" value="{{editMap[item.key].val}}" data-key="{{item.key}}" bindblur="changeNumber" type="digit" placeholder="请输入{{item.name}}" border="{{ false }}" />
+    </block>
+    <block wx:elif="{{item.type=='Boolean'}}">
+      <van-switch disabled="{{item.disabled}}" active-color="{{color}}" checked="{{ editMap[item.key].val }}" data-key="{{item.key}}" bind:change="switchChange" size="40rpx" />
+    </block>
+    <block wx:elif="{{item.type=='Array'}}">
+      <block wx:if="{{!item.view}}">
+        <view class="tags">
+          <block wx:for="{{editMap[item.key].val}}" wx:for-item="tag" wx:for-index="tag_index" wx:key="tag">
+            <van-tag type="primary" closeable="{{!item.disabled}}" size="medium" data-key="{{item.key}}" data-index="{{tag_index}}" bind:close="delTextarea" color="{{color}}" text-color="{{text_color}}">{{tag}}</van-tag>
+          </block>
+        </view>
+        <view class="text">
+          <textarea disabled="{{item.disabled}}" confirm-type="点击添加" data-key="{{item.key}}" bindconfirm="addTextarea" placeholder="请输入{{item.name}}" auto-height></textarea>
+        </view>
+      </block>
+      <block wx:elif="{{item.view=='edit-image'}}">
+        <block wx:if="{{item.disabled}}">
+          <image wx:for="{{editMap[item.key].val}}" wx:for-item="disabled_item" wx:for-index="disabled_index" wx:key="disabled_item" style="width:160rpx;height: 160rpx;margin-right: 10rpx;" src="{{disabled_item.url}}" mode="" />
+        </block>
+        <block wx:else>
+          <upload fileList="{{editMap[item.key].val}}" data-key="{{item.key}}" bind:onChangeFile="changeFile_array" accept="image" maxCount="9" uploadURL="{{uploadURL}}" domain="{{domain}}" uptokenURL="{{uptokenURL}}"></upload>
+        </block>
+
+      </block>
+      <block wx:elif="{{item.view=='pointer-array'}}">
+        <view class="tags">
+          <block wx:for="{{editMap[item.key].text}}" wx:for-item="tag" wx:for-index="tag_index" wx:key="tag">
+            <van-tag type="primary" closeable="{{!item.disabled}}" size="medium" data-key="{{item.key}}" data-index="{{tag_index}}" bind:close="delPointer" color="{{color}}" text-color="{{text_color}}">{{tag}}</van-tag>
+          </block>
+        </view>
+        <view class="btn_Pointer" wx:if="{{!item.disabled}}">
+          <button data-index="{{index}}" data-key="{{item.key}}" bind:tap="openPointer" style="background: {{color}};color: {{text_color}};">
+            <van-icon name="plus" />添加
+          </button>
+        </view>
+      </block>
+    </block>
+    <block wx:elif="{{item.type=='Pointer'}}">
+      <view class="text" data-index="{{index}}" data-key="{{item.key}}" bind:tap="openPointer">
+        <text class="title">{{editMap[item.key].text||'请选择'}}</text>
+        <van-icon name="arrow" />
+      </view>
     </block>
+  </view>
 </view>
-<view class="footer">
-    <van-button class="btn" size="large" color="#46a9a4" bindtap="submit">提交</van-button>
-</view>
+<block wx:if="{{is_btn}}">
+  <view class="footer">
+    <button class="btn" style="background: {{color}};color: {{text_color}};" bindtap="submit">提交</button>
+  </view>
+</block>
+
+<!-- 指针查询 -->
+<van-popup show="{{ isShowPointer }}" position="bottom" bind:close="closePointer" round>
+  <view class="popup">
+    <view class="title">选择内容</view>
+    <van-search bind:change="valChange" placeholder="请输入搜索关键词" />
+    <scroll-view class="itemBox" bindscrolltolower="getPointerItem" scroll-y>
+      <block wx:for="{{pointerList}}" wx:for-item="pointer_item" wx:key="pointer_item">
+        <view class="item" data-index="{{index}}" bind:tap="{{editFields[fieldIndex].type=='Array'?'checkPointer_Array':'checkPointer'}}" style="color:{{pointer_item.dev_router_check?color:'black'}};">
+          {{pointer_item.storeName||pointer_item.name||pointer_item.title||pointer_item.orderNum||pointer_item.mobile}}
+          <van-icon name="success" wx:if="{{pointer_item.dev_router_check}}" color="{{color}}" />
+        </view>
+      </block>
+    </scroll-view>
+  </view>
+</van-popup>

+ 96 - 111
nova-tourism/components/dev-route/index.wxss

@@ -1,144 +1,129 @@
-.red {
-  color: #F01740;
+.item {
+  margin: 20rpx;
+  border-bottom: 1rpx solid whitesmoke;
+  padding-bottom: 20rpx;
 }
-.grey {
-  color: #666666;
+.item .name {
+  font-size: 28rpx;
+  padding-bottom: 10rpx;
 }
-.black {
-  color: #000000;
+.item .content {
+  padding: 0 20rpx;
 }
-.title {
-  font-weight: Medium;
-  font-size: 36rpx;
-  color: #222222;
+.item .content .text {
+  display: flex;
+  align-items: flex-end;
 }
-.text-large {
-  font-size: 36rpx;
+.item .content .text > textarea {
+  width: 550rpx;
+  padding: 10rpx;
+  margin: 5rpx 0;
+  font-size: 26rpx;
+  min-height: 100rpx;
+  background: whitesmoke;
 }
-.text {
-  font-size: 30rpx;
+.item .content .text .btn {
+  margin: 0 10rpx;
+  padding: 5rpx 10rpx;
+  font-size: 26rpx;
+  background: #46a9a4;
 }
-.text-left {
-  text-align: left;
+.item .content .text .title {
+  margin-right: 20rpx;
+  font-size: 26rpx;
 }
-.text-center {
-  text-align: center;
+.item .content .radioGroup .radio {
+  font-size: 26rpx;
+  padding: 5rpx;
 }
-.text-small {
-  font-size: 24rpx;
-  /* word-break: keep-all; */
+.item .content .tags {
+  margin-bottom: 10rpx;
 }
-.flex {
-  display: flex;
+.item .content .tags van-tag {
+  margin-right: 10rpx;
 }
-.justify-between {
-  justify-content: space-between;
+.item .content .btn_Pointer {
+  width: 50vw;
 }
-.flex-aligin-center {
-  display: flex;
-  align-items: center;
+.item .content .btn_Pointer button {
+  font-size: 26rpx;
+  width: 50vw;
 }
-.flex-justify-between {
-  display: flex;
-  justify-content: space-between;
+.item .content .specMap .tip {
+  font-size: 26rpx;
+  color: red;
 }
-.flex-1 {
-  flex: 1;
+.item .content .specMap .list .tags .title {
+  font-weight: bold;
+  font-size: 26rpx;
 }
-.flex-grow-1 {
-  flex-grow: 1;
+.item .content .specMap .obj .title {
+  margin: 10rpx 0;
+  font-weight: bold;
+  font-size: 26rpx;
 }
-.fixed-bottom {
-  position: fixed;
-  bottom: 0;
-  left: 0;
-  right: 0;
+.item .content .specMap .obj .obj_item {
+  margin: 10rpx;
+  padding: 10rpx;
+  background: whitesmoke;
 }
-.w-100 {
-  width: 100%;
+.item .content .specMap .obj .obj_item .key {
+  font-weight: bold;
+  font-size: 26rpx;
 }
-.h-100 {
-  height: 100%;
+.item .content .specMap .obj .obj_item .info .info_item {
+  display: flex;
+  padding: 10rpx 0;
+  border-bottom: 1rpx solid white;
+  position: relative;
 }
-.page-section {
-  margin: 20rpx;
-  border-radius: 20rpx;
-  background-color: #ffffff;
+.item .content .specMap .obj .obj_item .info .info_item > view {
+  margin: 0 3rpx;
 }
-.page-section-spacing {
-  padding: 20rpx;
+.item .content .specMap .obj .obj_item .info .info_item > view > text {
+  font-size: 26rpx;
 }
-.spacing-small {
+.item .content .specMap .obj .obj_item .info .info_item > view > input {
+  border: 1rpx solid #c9c9c9;
   padding: 10rpx;
+  font-size: 26rpx;
 }
-.border-trans {
-  border: 1px solid transparent;
-}
-.ellipsis {
-  width: 100%;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  display: -webkit-box;
-  -webkit-line-clamp: 1;
-  -webkit-box-orient: vertical;
-}
-.ellipsis-2 {
-  width: 100%;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  display: -webkit-box;
-  -webkit-line-clamp: 2;
-  -webkit-box-orient: vertical;
-}
-.form {
+.item .content .specMap .obj .obj_item .info .info_item .del {
+  width: 40rpx;
+  height: 40rpx;
+  background: #cfcfcf;
   display: flex;
-  flex-wrap: wrap;
+  justify-content: center;
+  position: absolute;
+  right: 0;
+  top: 0;
 }
-.form .col-12 {
+.item .content .specMap .obj .obj_item .info .btn_specMap {
   width: 50%;
 }
-.form-item {
+.item .content .specMap .obj .obj_item .info .btn_specMap > button {
+  font-size: 26rpx;
+}
+.popup {
   width: 100%;
-  margin: 20rpx 0;
-  color: #382E2E;
+  height: 70vh;
 }
-.form-item .form-label {
+.popup .title {
   font-size: 28rpx;
-  margin: 20rpx;
-  color: #666666;
-}
-.form-item .form-label .required {
-  font-size: 40rpx;
-  vertical-align: middle;
-}
-.form-item .form-field {
-  padding: 10rpx;
-}
-.form-item .form-field .form-input {
-  padding: 10rpx;
-  border: 0.5px solid #eee;
-  border-radius: 10rpx;
-}
-.form-item .form-field .form-input-num {
-  width: 200rpx;
-}
-.tag-wrapper {
-  display: flex;
-  align-items: center;
-  color: #382E2E;
-}
-.tag-wrapper .add-btn {
-  width: auto;
+  height: 90rpx;
+  line-height: 90rpx;
+  text-align: center;
+  border-bottom: 1rpx solid whitesmoke;
 }
-.tag-wrapper .tags {
-  flex: 1;
-  display: flex;
-  flex-wrap: wrap;
+.popup .itemBox {
+  overflow-y: auto;
+  height: calc(70vh - 250rpx);
 }
-.tag-wrapper .tags .tag {
-  margin: 10rpx;
+.popup .itemBox .item {
+  font-size: 26rpx;
+  border-bottom: 1rpx solid whitesmoke;
 }
-.footer {
-  margin-bottom: 100rpx;
-  padding: 20rpx;
+.footer .btn {
+  width: 100vw;
+  border-radius: 0;
 }

+ 31 - 2
nova-tourism/pages/my/merchant/good/good-edit/index.js

@@ -5,14 +5,43 @@ Page({
    * 页面的初始数据
    */
   data: {
-
+    edit_field_map: {
+      // isRecom:{
+      //   isHide:true,//是否隐藏 - 此项非DevRouter编辑
+      //   disabled: true,//禁止编辑
+      //   required: true,//必填项
+      //   default:true,//默认值
+      // },
+      isRecom: {
+        isHide: true
+      },
+      isHome: {
+        isHide: true
+      },
+      name: {
+        default: '杯子杯子'
+      },
+      status: {
+        disabled: true
+      },
+      shopStore:{
+        disabled: true,
+      }
+    }, //设置默认编辑对象
+    isShow:false
   },
 
   /**
    * 生命周期函数--监听页面加载
    */
   onLoad(options) {
-
+    let store = wx.getStorageSync('store')
+    let {edit_field_map}=this.data
+    edit_field_map.shopStore['default']={__type:'Pointer',className:'ShopStore',objectId:store?.objectId}
+    console.log(options)
+    let {gid} = this.options
+    this.setData({gid,edit_field_map})
+    console.log(this.data.gid)
   },
 
   /**

+ 3 - 1
nova-tourism/pages/my/merchant/good/good-edit/index.json

@@ -1,3 +1,5 @@
 {
-  "usingComponents": {}
+  "usingComponents": {
+    "dev-route":"../../../../../components/dev-route/index"
+  }
 }

+ 5 - 1
nova-tourism/pages/my/merchant/good/good-edit/index.wxml

@@ -1,2 +1,6 @@
 <!--nova-tourism/pages/my/merchant/good/good-edit/index.wxml-->
-<text>nova-tourism/pages/my/merchant/good/good-edit/index.wxml</text>
+<nav type="back" background-color="#46a9a4" title="编辑商品" />
+<block >
+  <dev-route rid='YLwqf9HhQD' object_id="{{gid}}" edit_field_map="{{edit_field_map}}" is_btn="{{true}}"></dev-route>
+</block>
+<!-- <suggest store_id="{{objectId}}"></suggest> -->

+ 113 - 0
nova-tourism/pages/my/merchant/good/good-list/index.js

@@ -0,0 +1,113 @@
+// nova-tourism/pages/my/merchant/good/good-list/index.js
+let Parse = getApp().Parse;
+const company = getApp().globalData.company
+const uid = Parse.User.current()?.id
+Page({
+
+  /**
+   * 页面的初始数据
+   */
+  data: {
+    goodList:[]
+  },
+
+  /**
+   * 生命周期函数--监听页面加载
+   */
+  onLoad(options) {
+  },
+
+  async refersh(){
+    let merchant = wx.getStorageSync('merchant')
+
+    if (!merchant) {
+      wx.showToast({
+        title: '商户有误',
+        icon: 'error'
+      })
+      setTimeout(() => {
+        wx.reLaunch({
+          url: `/nova-tourism/pages/index/index`
+        })
+      }, 1000);
+      return
+    }
+    this.getGoods()
+  },
+
+  /**获取商品 */
+  async getGoods() {
+    let {goodList}=this.data
+    let store = wx.getStorageSync('store')
+    let query = new Parse.Query('ShopGoods')
+    query.equalTo('company', company)
+    query.notEqualTo('isDeleted', true)
+    query.equalTo('shopStore',store?.objectId)
+    query.ascending('top')
+    query.limit(15)
+    query.skip(goodList?.length||0)
+    let d = await query.find()
+    let list = d?.map(item=>item.toJSON())
+    console.log(list)
+    this.setData({
+      goodList:[...goodList,...(list||[])]
+    })
+  },
+  /** 跳转*/
+  tourl(e) {
+    const url = e.currentTarget.dataset.url
+    wx.navigateTo({
+      url: `${url}` // 目标页面的路径
+    });
+  },
+
+  /**
+   * 生命周期函数--监听页面初次渲染完成
+   */
+  onReady() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面显示
+   */
+  onShow() {
+    this.refersh()
+
+  },
+
+  /**
+   * 生命周期函数--监听页面隐藏
+   */
+  onHide() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面卸载
+   */
+  onUnload() {
+
+  },
+
+  /**
+   * 页面相关事件处理函数--监听用户下拉动作
+   */
+  onPullDownRefresh() {
+
+  },
+
+  /**
+   * 页面上拉触底事件的处理函数
+   */
+  onReachBottom() {
+    this.getGoods()
+  },
+
+  /**
+   * 用户点击右上角分享
+   */
+  onShareAppMessage() {
+
+  }
+})

+ 3 - 0
nova-tourism/pages/my/merchant/good/good-list/index.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 78 - 0
nova-tourism/pages/my/merchant/good/good-list/index.less

@@ -0,0 +1,78 @@
+.add-customer {
+    margin: 20rpx;
+    padding: 20rpx 0;
+    text-align: center;
+    color: blue;
+    background-color: #eee;
+    border-radius: 40rpx;
+
+    .add-icon {
+        margin-right: 10rpx;
+    }
+
+}
+
+.good {
+    margin: 20rpx;
+    display: flex;
+    justify-content: space-between;
+    // box-shadow: 0rpx 0rpx 10rpx rgb(180, 180, 180);
+    // border-radius: 20rpx;
+    .image {
+        border-radius: 20rpx;
+        width: 200rpx;
+        height: 200rpx;
+    }
+
+    .info {
+        padding: 10rpx 0;
+        width: 480rpx;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-between;
+
+        .up {
+            .name {
+                font-size: 28rpx;
+                overflow: hidden;
+                white-space: nowrap;
+                text-overflow: ellipsis;
+            }
+
+            .tag {
+                display: flex;
+                flex-wrap: wrap;
+                text {
+                    margin-top: 10rpx;
+                    font-size: 22rpx;
+                    color: rgb(90, 90, 90);
+                    margin-right: 15rpx;
+                }
+            }
+        }
+
+        .down {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+
+            .price {
+                color: red;
+                font-size: 22rpx;
+
+                text {
+                    font-size: 25rpx;
+                    font-weight: bold;
+                }
+            }
+
+            .btn {
+                width: 200rpx;
+
+                button {
+                    font-size: 25rpx;
+                }
+            }
+        }
+    }
+}

+ 26 - 0
nova-tourism/pages/my/merchant/good/good-list/index.wxml

@@ -0,0 +1,26 @@
+<nav type="back" background-color="#46a9a4" title="商品管理" />
+<view class="page-section">
+  <view class="add-customer" bind:tap="addRoom">
+    <van-icon class="add-icon" name="https://file-cloud.fmode.cn/sHNeVwSaAg/20220418/qn1d5i021341.png?imageView2/1/w/200/h/200" color="#3d88ff" />
+    <text class="text" style="color:#3d88ff;" data-url="/nova-tourism/pages/my/merchant/good/good-edit/index" bindtap="tourl">添加商品</text>
+  </view>
+</view>
+
+<block wx:for="{{goodList}}" wx:key="index">
+  <view class="good">
+    <image class="image" src="{{item.image||'https://file-cloud.fmode.cn/EbxZUK5lBI/20250321/vdq1j1110711455.jpg'}}" mode="widthFix" />
+    <view class="info">
+      <view class="up">
+        <view class="name">{{item.name||''}}</view>
+        <view class="tag">
+          <text wx:for="{{item.specMap.specList}}" wx:for-item="spec" wx:key="spec">{{spec}}</text>
+        </view>
+      </view>
+      <view class="down">
+        <view class="price">¥<text>{{item.price||0}}</text></view>
+        <view class="btn"><button data-url="/nova-tourism/pages/my/merchant/good/good-edit/index?gid={{item.objectId}}" bindtap="tourl">编 辑 详 情</button></view>
+      </view>
+    </view>
+  </view>
+</block>
+<view style="height: 50rpx;"></view>

+ 63 - 0
nova-tourism/pages/my/merchant/good/good-list/index.wxss

@@ -0,0 +1,63 @@
+.add-customer {
+  margin: 20rpx;
+  padding: 20rpx 0;
+  text-align: center;
+  color: blue;
+  background-color: #eee;
+  border-radius: 40rpx;
+}
+.add-customer .add-icon {
+  margin-right: 10rpx;
+}
+.good {
+  margin: 20rpx;
+  display: flex;
+  justify-content: space-between;
+}
+.good .image {
+  border-radius: 20rpx;
+  width: 200rpx;
+  height: 200rpx;
+}
+.good .info {
+  padding: 10rpx 0;
+  width: 480rpx;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+}
+.good .info .up .name {
+  font-size: 28rpx;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+.good .info .up .tag {
+  display: flex;
+  flex-wrap: wrap;
+}
+.good .info .up .tag text {
+  margin-top: 10rpx;
+  font-size: 22rpx;
+  color: #5a5a5a;
+  margin-right: 15rpx;
+}
+.good .info .down {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.good .info .down .price {
+  color: red;
+  font-size: 22rpx;
+}
+.good .info .down .price text {
+  font-size: 25rpx;
+  font-weight: bold;
+}
+.good .info .down .btn {
+  width: 200rpx;
+}
+.good .info .down .btn button {
+  font-size: 25rpx;
+}

+ 6 - 0
nova-tourism/pages/my/merchant/merchant-home/index.js

@@ -205,6 +205,12 @@ Page({
     //     });
 
     // },
+    goodmanage() {
+      wx.navigateTo({
+          url: '../good/good-list/index'
+      });
+
+  },
     roommanage() {
         wx.navigateTo({
             url: '../room-manage/index'

+ 9 - 0
nova-tourism/pages/my/merchant/merchant-home/index.wxml

@@ -127,6 +127,15 @@
         <van-icon name="arrow" />
       </view>
     </block>
+    <block wx:if="{{store.type=='stay'}}">
+      <view class="box-title" bindtap="goodmanage">
+        <view class="box-details">
+          <van-icon name="https://file-cloud.fmode.cn/sHNeVwSaAg/20230705/7d11hf112459718.png" size="20" />
+          <view class="name">商超管理</view>
+        </view>
+        <van-icon name="arrow" />
+      </view>
+    </block>
 
     <view class="box-title" data-url="/nova-tourism/pages/my/merchant/merchant-home/my-users/index" bindtap="gourl">
       <view class="box-details">

+ 3 - 3
project.private.config.json

@@ -8,9 +8,9 @@
     "miniprogram": {
       "list": [
         {
-          "name": "nova-tourism/pages/my/my-order/my-refund/refund-good/index",
-          "pathName": "nova-tourism/pages/my/my-order/my-refund/refund-good/index",
-          "query": "oid=qzN0MnYEba",
+          "name": "nova-tourism/pages/my/merchant/good/good-list/index",
+          "pathName": "nova-tourism/pages/my/merchant/good/good-list/index",
+          "query": "",
           "launchMode": "default",
           "scene": null
         }