Bladeren bron

Merge branch 'dev' of 113.31.163.91:quanshu/mp-ui-pc into dev

chunping 3 jaren geleden
bovenliggende
commit
ead830aac7

+ 5 - 0
package-lock.json

@@ -1418,6 +1418,11 @@
       "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==",
       "dev": true
     },
+    "@tinymce/tinymce-vue": {
+      "version": "3.2.8",
+      "resolved": "https://registry.npmjs.org/@tinymce/tinymce-vue/-/tinymce-vue-3.2.8.tgz",
+      "integrity": "sha512-jEz+NZ0g+FZFz273OEUWz9QkwPMyjc5AJYyxOgu51O1Y5UaJ/6IUddXTX6A20mwCleEv5ebwNYdalviafx4fnA=="
+    },
     "@types/glob": {
       "version": "7.1.4",
       "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz",

+ 1 - 0
package.json

@@ -44,6 +44,7 @@
     "@fullcalendar/timeline": "^4.3.0",
     "@fullcalendar/vue": "^4.3.1",
     "@riophae/vue-treeselect": "0.4.0",
+    "@tinymce/tinymce-vue": "^3.2.3",
     "axios": "^0.21.1",
     "clipboard": "2.0.6",
     "core-js": "3.8.1",

+ 1 - 0
public/index.html

@@ -6,6 +6,7 @@
     <meta name="renderer" content="webkit">
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <script src="<%= BASE_URL %>tinymce.min.js"></script>
     <title><%= webpackConfig.name %></title>
     <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
 	  <style>

File diff suppressed because it is too large
+ 8 - 0
public/tinymce.min.js


+ 72 - 0
src/components/TinyEditor.vue

@@ -0,0 +1,72 @@
+<template>
+  <TinyEditor v-model="content" :placeholder="placeholder" api-key="ushn75pw8xd7ec18wwdatp7bi75o98pm0ob10zncyyrbkj4k" :init="options" />
+</template>
+<script>
+import TinyEditor from '@tinymce/tinymce-vue'
+import { publicFileSaveAPI } from '@/api/common'
+import { publicFileGetUrl } from "@/api/common"
+import { getToken } from '@/utils/auth'
+export default {
+  components: {
+    TinyEditor
+  },
+  props: {
+    value: {
+      default: '',
+      type: String
+    },
+    height: {
+      default: 800,
+      type: Number
+    },
+    placeholder: {
+      default: '',
+      type: String
+    }
+  },
+  data() {
+    return {
+      options: {
+        base_url: '//itie-static.oss-cn-hangzhou.aliyuncs.com/assets/tinymce/',
+        language: 'zh_CN',
+        language_url: '//itie-static.oss-cn-hangzhou.aliyuncs.com/assets/tinymce/zh_CN.js',
+        height: 500,
+        resize: true,
+        statusbar: false,
+        // skin_url: '//itie-static.oss-cn-hangzhou.aliyuncs.com/assets/tinymce/oxide-dark', // 暗色皮肤
+        // content_css: '//itie-static.oss-cn-hangzhou.aliyuncs.com/assets/tinymce/content.css',
+        plugins: ['advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount placeholder indent2em'], // 插件
+        image_advtab: true,
+        images_upload_handler: this.updateImage,
+        imagetools_toolbar: '',
+        fontsize_formats: '8px 10px 12px 14px 16px 18px 20px 22px 24px 36px',
+        toolbar: ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent  blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen indent2em']
+      }
+    }
+  },
+  computed: {
+    content: {
+      get() {
+        return this.value
+      },
+      set(val) {
+        this.$emit('input', val)
+      }
+    }
+  },
+  methods: {
+    updateImage(blobInfo, success, failure) {
+      publicFileSaveAPI(
+        { file: blobInfo.blob() },
+        {
+          "Authorization": "Bearer " + getToken(),
+          "x-zz-timestamp": new Date().valueOf()
+        }).then(res => {
+        success(publicFileGetUrl + res.data.fileName)
+      }).catch(err => {
+        failure(err)
+      })
+    }
+  }
+}
+</script>

+ 18 - 12
src/views/business/coupon/add.vue

@@ -9,8 +9,8 @@
           </el-form-item>
           <el-form-item label="使用场景:" prop="type">
             <el-radio-group v-model="addData.type" :disabled="readonly">
-              <el-radio :label="1">门店消费</el-radio>
-              <el-radio :label="2">盲票购买</el-radio>
+              <el-radio :label="2">门店消费</el-radio>
+              <el-radio :label="1">盲票购买</el-radio>
             </el-radio-group>
           </el-form-item>
           <el-form-item label="面值:" prop="discount">
@@ -26,8 +26,8 @@
           <!-- <el-form-item label="图片:" prop="picUrl">
             <Upload :value="addData.picUrl ? [{ fileName: addData.picUrl }] : []" @input="addData.picUrl = $event[0] ? $event[0].fileName : ''" :limit="1" />
           </el-form-item> -->
-          <el-form-item v-if="addData.type === 1" label="门店默认承担比例:" prop="channelSharedRate">
-            <el-input v-model.number="addData.channelSharedRate" :readonly="readonly" type="number" placeholder="请输入门店默认承担比例">
+          <el-form-item v-if="addData.type === 2" label="门店默认承担比例:" prop="channelSharedRate">
+            <el-input v-model="addData.channelSharedRate" :readonly="readonly" type="number" placeholder="请输入门店默认承担比例">
               <template slot="append">%</template>
             </el-input>
             <div class="tip">若门店承担100%,则核销后公司不需要打款给门店,依此类推。</div>
@@ -47,7 +47,7 @@
           <el-form-item label="使用说明:" prop="description">
             <el-input type="textarea" rows="4" :readonly="readonly" v-model="addData.description" placeholder="请输入使用说明 对用户可见"/>
           </el-form-item>
-          <el-form-item v-if="addData.type === 1" label="使用范围:" prop="useArea">进票门店</el-form-item>
+          <el-form-item v-if="addData.type === 2" label="使用范围:" prop="useArea">进票门店</el-form-item>
           <el-form-item v-else label="使用范围:" prop="useArea">
             <el-radio-group v-model="addData.useArea" :disabled="readonly">
               <el-radio :label="0">所有盲票</el-radio>
@@ -123,13 +123,16 @@ export default {
         type: [{ required: true, message: '请输入券类型', trigger: 'blur' }],
         quantity: [
           { required: true, message: '请输入券发放数量', trigger: 'blur' },
-          { min: 0, message: '请输入正确的数量', trigger: 'blur' }
+          { pattern: /^([1-9]\d*)$/, message: "请输入正确的数量", trigger: ["blur", "change"] }
         ],
         discount: [
           { required: true, message: '请输入券面值', trigger: 'blur' },
           { pattern: /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的面值,最多两位小数", trigger: ["blur", "change"] }
         ],
-        channelSharedRate: [{ required: true, message: '请输入门店默认承担比例', trigger: 'blur' }],
+        channelSharedRate: [
+          { required: true, message: '请输入门店默认承担比例', trigger: 'blur' },
+          { pattern: /^100$|^(\d|[1-9]\d)(\.\d+)*$/, message: "请输入正确的百分比数字", trigger: ["blur", "change"] }
+        ],
         minOrderAmt: [
           { required: true, message: '请输入最低消费金额', trigger: 'blur' },
           { pattern: /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的金额,最多两位小数", trigger: ["blur", "change"] }
@@ -138,7 +141,7 @@ export default {
           { required: true, message: '请输入有效期', trigger: 'blur' },
           { pattern: /^([1-9]\d*)$/, message: "请输入正确的数字", trigger: ["blur", "change"] }
         ],
-        description: [{ required: true, message: '请输入使用说明', trigger: 'blur' }],
+        description: [{ required: false, message: '请输入使用说明', trigger: 'blur' }],
         useArea: [{ required: true, message: '请选择使用范围', trigger: 'blur' }]
       }
     }
@@ -146,9 +149,12 @@ export default {
   created() {
     if (this.id) {
       getCouponDetail(this.id).then(res => {
-        this.addData = res.data
-        this.addData.type = JSON.parse(res.data.type).value
-        this.addData.useArea = JSON.parse(res.data.useArea).value
+        const { couponId, title, quantity, discount, channelSharedRate, minOrderAmt, dueDays, description, ticketBoxList } = res.data
+        this.addData = {
+          type: JSON.parse(res.data.type).value,
+          useArea: JSON.parse(res.data.useArea).value,
+          couponId, title, quantity, discount, channelSharedRate, minOrderAmt, dueDays, description, ticketBoxList
+        }
       })
     }
   },
@@ -164,7 +170,7 @@ export default {
             this.addIng = false
             if (res.code === 0) {
               this.$message({
-                message: this.addData.id ? '修改成功!' : '添加成功!',
+                message: this.addData.couponId ? '修改成功!' : '添加成功!',
                 type: 'success'
               })
               this.$router.go(-1)

+ 2 - 2
src/views/business/coupon/index.vue

@@ -65,9 +65,9 @@
         <template slot-scope="{row}">
           <el-button v-hasPermi="['business:coupon:query']" type="text" @click="$router.push('/coupon/view?id=' + row.couponId)">查看</el-button>
           <el-button v-if="JSON.parse(row.status).value === 'init'" v-hasPermi="['business:coupon:edit']" type="text" @click="$router.push('/coupon/edit?id=' + row.couponId)">编辑</el-button>
-          <el-button v-if="JSON.parse(row.status).value === 'off'" v-hasPermi="['business:coupon:on']" type="text" @click="setStatus(row, 'on')">上架</el-button>
+          <el-button v-if="JSON.parse(row.status).value === 'off' || JSON.parse(row.status).value === 'init'" v-hasPermi="['business:coupon:on']" type="text" @click="setStatus(row, 'on')">上架</el-button>
           <el-button v-if="JSON.parse(row.status).value === 'on'" v-hasPermi="['business:coupon:off']" type="text" @click="setStatus(row, 'off')">下架</el-button>
-          <el-button v-if="JSON.parse(row.status).value === 'off'" v-hasPermi="['business:coupon:remove']" class="del" type="text" @click="del(row)">删除</el-button>
+          <el-button v-if="JSON.parse(row.status).value === 'init'" v-hasPermi="['business:coupon:remove']" class="del" type="text" @click="del(row)">删除</el-button>
         </template>
       </el-table-column>
     </el-table>

+ 54 - 306
src/views/business/goods/add.vue

@@ -34,7 +34,7 @@
       <el-row :gutter="40">
         <el-col :span="23">
           <el-form-item label="启用多SKU:" prop="multiSku">
-            <!-- <el-switch
+            <el-switch
               v-model="addData.multiSku"
               active-color="#13ce66"
               inactive-color="#ff4949"
@@ -42,15 +42,12 @@
               :inactive-value="0"
               active-text="是"
               inactive-text="否"
-            /> -->
-            <el-radio-group v-model="addData.multiSku">
-              <el-radio-button :label="0">单规格</el-radio-button>
-              <el-radio-button :label="1">多规格</el-radio-button>
-            </el-radio-group>
+            />
           </el-form-item>
         </el-col>
       </el-row>
-      <el-row v-if="!multipleSpec" :gutter="40">
+      <Spec :multiSku="addData.multiSku" />
+      <el-row v-if="addData.multiSku === 0" :gutter="40">
         <el-col :span="23">
           <el-form-item label="价格:" prop="value">
             <el-input v-model="addData.value" type="number" placeholder="请输入商品价格">
@@ -59,117 +56,36 @@
           </el-form-item>
         </el-col>
         <el-col :span="23">
-          <el-form-item label="成本:" prop="cost">
-            <el-input v-model.number="addData.cost" type="number" placeholder="请输入商品成本">
-              <template slot="append"></template>
+          <el-form-item label="兑换价格:" prop="exchangePrice">
+            <el-input v-model="addData.exchangePrice" type="number" placeholder="请输入兑换价格">
+              <template slot="append">盲豆</template>
             </el-input>
           </el-form-item>
         </el-col>
-        <!-- <el-col :span="23">
-          <el-form-item label="原兑换价格:" prop="originPrice">
-            <el-input v-model="addData.originPrice" type="number" placeholder="请输入原兑换价格">
+        <el-col :span="23">
+          <el-form-item label="成本:" prop="cost">
+            <el-input v-model.number="addData.cost" type="number" placeholder="请输入商品成本">
               <template slot="append">元</template>
             </el-input>
           </el-form-item>
-        </el-col> -->
+        </el-col>
         <el-col :span="23">
-          <el-form-item label="兑换价格:" prop="exchangePrice">
-            <el-input v-model="addData.exchangePrice" type="number" placeholder="请输入兑换价格">
-              <template slot="append"></template>
+          <el-form-item label="库存:" prop="quantity">
+            <el-input v-model="addData.quantity" type="number" placeholder="请输入商品库存">
+              <template slot="append"></template>
             </el-input>
           </el-form-item>
         </el-col>
+      </el-row>
+      <el-divider content-position="left">商品详情</el-divider>
+      <el-row>
         <el-col :span="23">
-          <el-form-item label="库存:" prop="quantity">
-            <el-input-number v-model="addData.quantity" placeholder="请输入商品库存" />
+          <el-form-item prop="description">
+            <TinyEditor v-model="addData.description" />
           </el-form-item>
         </el-col>
       </el-row>
     </el-form>
-    <div v-if="multipleSpec">
-      <div style="margin-bottom: 16px">
-        <el-button :plain="true" type="primary" size="small" @click="handleSpecificationShow">添加规格</el-button>
-      </div>
-      <el-table :data="specifications">
-        <el-table-column property="specification" label="规格名"/>
-        <el-table-column property="value" label="规格值">
-          <template slot-scope="scope">
-            <el-tag type="primary">
-              {{ scope.row.value }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column align="center" label="操作" width="120">
-          <template slot-scope="scope">
-            <el-button type="danger" size="small" @click="handleSpecificationDelete(scope.row)">删除</el-button>
-          </template>
-        </el-table-column>
-      </el-table>
-    </div>
-    <el-dialog :visible.sync="specVisiable" title="设置规格" :close-on-click-modal="false" width="400px">
-      <el-form ref="specForm" :model="specForm" label-width="80px">
-        <el-form-item label="规格名:" prop="specification">
-          <el-input v-model="specForm.specification"/>
-        </el-form-item>
-        <el-form-item label="规格值:" prop="value">
-          <el-input v-model="specForm.value"/>
-          <div class="tip">多个规格值请用逗号隔开</div>
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button @click="specVisiable = false">取消</el-button>
-        <el-button type="primary" @click="handleSpecificationAdd">确定</el-button>
-      </div>
-    </el-dialog>
-    <br>
-    <el-table v-if="multipleSpec" :data="products">
-      <el-table-column property="name" label="sku名称" />
-      <el-table-column property="picUrl" width="100" label="商品图片">
-        <template slot-scope="scope">
-          <img v-if="scope.row.picUrl" :src="IMG_URL+scope.row.picUrl" width="40">
-        </template>
-      </el-table-column>
-      <el-table-column property="value" label="价格"/>
-      <!-- <el-table-column property="originPrice" label="原兑换价格"/> -->
-      <el-table-column property="exchangePrice" label="兑换价格"/>
-      <el-table-column property="cost" label="成本"/>
-      <el-table-column property="quantity" label="库存数量"/>
-      <el-table-column align="center" label="操作" width="120">
-        <template slot-scope="scope">
-          <el-button type="primary" size="mini" @click="handleProductShow(scope.row)">设置</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <el-dialog :visible.sync="productVisiable" title="设置商品" :close-on-click-modal="false" width="400px">
-      <el-form ref="productForm" :model="productForm" label-width="100px">
-        <el-form-item label="sku名称:" prop="name">
-          <el-input v-model="productForm.name" />
-        </el-form-item>
-        <el-form-item label="价格:" prop="value">
-          <el-input-number v-model="productForm.value" />
-        </el-form-item>
-        <!-- <el-form-item label="原兑换价格:" prop="originPrice">
-          <el-input-number v-model="productForm.originPrice"/>
-        </el-form-item> -->
-        <el-form-item label="兑换价格:" prop="exchangePrice">
-          <el-input-number v-model="productForm.exchangePrice"/>
-        </el-form-item>
-        <el-form-item label="成本:" prop="cost">
-          <el-input-number v-model="productForm.cost"/>
-        </el-form-item>
-        <el-form-item label="库存数量:" prop="quantity">
-          <el-input-number v-model="productForm.quantity"/>
-        </el-form-item>
-        <el-form-item label="商品图片:" prop="picUrl">
-          <Upload :value="productForm.picUrl ? [{ fileName: productForm.picUrl }] : []" @input="productForm.picUrl = $event[0] ? $event[0].fileName : ''" :limit="1" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button @click="productVisiable = false">取消</el-button>
-        <el-button type="primary" @click="handleProductEdit">确定</el-button>
-      </div>
-    </el-dialog>
     <br>
     <el-row>
       <el-col :span="24" style="text-align: right">
@@ -181,37 +97,50 @@
 </template>
 <script>
 import Upload from '@/components/ImageUpload'
+import Spec from './components/spec'
+import TinyEditor from '@/components/TinyEditor'
 import { getGoodsDetail, addGoods } from '@/api/business/goods'
 import { publicFileGetUrl } from "@/api/common"
 export default {
   components: {
-    Upload
+    TinyEditor,
+    Upload,
+    Spec
   },
   data() {
     return {
       IMG_URL: publicFileGetUrl,
       id: this.$route.query.id,
       addData: {
-        multiSku: 0
+        multiSku: 0,
+        description: ''
       },
       rules: {
-        title: [{ required: true, message: '请输入商品名称', trigger: 'blur' }]
-      },
-      dragOptions: {
-        animation: 100,
-      },
-      specifications: [],
-      products: [],
-      specVisiable: false, // 规格弹窗
-      specForm: {}, // 规格暂存
-      productVisiable: false,
-      productForm: {},
+        title: [{ required: true, message: '请输入商品名称', trigger: 'blur' }],
+        picUrl: [{ required: true, message: '请上传商品图片', trigger: 'change' }],
+        exchangeShow: [{ required: true, message: '请选择是否支持盲豆兑换', trigger: 'change' }],
+        multiSku: [{ required: true, message: '请选择SKU类型', trigger: 'change' }],
+        value: [
+          { required: true, message: '请输入商品价格', trigger: 'blur' },
+          { pattern: /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的金额,最多两位小数", trigger: ["blur", "change"] }
+        ],
+        exchangePrice: [
+          { required: true, message: '请输入兑换价格', trigger: 'blur' },
+          { pattern: /^([1-9]\d*)$/, message: "请输入正确的数字", trigger: ["blur", "change"] }
+        ],
+        cost: [
+          { required: true, message: '请输入成本', trigger: 'blur' },
+          { pattern: /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/, message: "请输入正确的金额,最多两位小数", trigger: ["blur", "change"] }
+        ],
+        quantity: [
+          { required: true, message: '请输入库存', trigger: 'blur' },
+          { pattern: /^([1-9]\d*)$/, message: "请输入正确的数字", trigger: ["blur", "change"] }
+        ],
+        description: [{ required: true, message: '请输入商品详情', trigger: 'blur' }]
+      }
     }
   },
   computed: {
-    multipleSpec() {
-      return this.addData.multiSku === 1
-    },
     mainPicUrl: {
       get() {
         return this.addData.picUrl ? this.addData.picUrl.split(',').map(item => {
@@ -221,153 +150,25 @@ export default {
         }) : []
       },
       set(val) {
-        this.addData.picUrl = val.map(item => { return item.fileName }).toString()
+        this.$set(this.addData, 'picUrl', val.map(item => { return item.fileName }).toString())
       }
     }
   },
   created() {
     if (this.id) {
       getGoodsDetail(this.id).then(res => {
-        this.addData = res.data
+        const { goodsId, title, picUrl, exchangeShow, multiSku, value, exchangePrice, cost, quantity, description } = res.data
+        this.addData = { goodsId, title, picUrl, exchangeShow, multiSku, value, exchangePrice, cost, quantity, description }
       })
     }
   },
   methods: {
-    beforeUpload(e) {
-      if (e.size > 1024000) {
-        this.$message({
-          message: '图片过大,请调整大小确保不超过1M!',
-          type: 'warning'
-        });
-        return false
-      }
-    },
-    handleSpecificationShow() {
-      this.specForm = {}
-      this.specVisiable = true
-    },
-    handleSpecificationDelete(row) {
-      const index = this.specifications.indexOf(row)
-      this.specifications.splice(index, 1)
-      this.specToProduct()
-    },
-    specToProduct() {
-      if (this.specifications.length === 0) {
-        return
-      }
-      // 根据specifications创建临时规格列表
-      var specValues = []
-      var spec = this.specifications[0].specification
-      var values = []
-      values.push(0)
-
-      for (var i = 1; i < this.specifications.length; i++) {
-        const aspec = this.specifications[i].specification
-
-        if (aspec === spec) {
-          values.push(i)
-        } else {
-          specValues.push(values)
-          spec = aspec
-          values = []
-          values.push(i)
-        }
-      }
-      specValues.push(values)
-
-      // 根据临时规格列表生产商品规格
-      // 算法基于 https://blog.csdn.net/tyhj_sf/article/details/53893125
-      var productsIndex = 0
-      var products = []
-      var combination = []
-      var n = specValues.length
-      for (var s = 0; s < n; s++) {
-        combination[s] = 0
-      }
-      var index = 0
-      var isContinue = false
-      do {
-        var specifications = []
-        var properties = ''
-        for (var x = 0; x < n; x++) {
-          var z = specValues[x][combination[x]]
-          specifications.push(this.specifications[z].value)
-          properties = `${properties ? (properties + ';') : ''}${this.specifications[z].specification}:${this.specifications[z].value}`
-        }
-        products[productsIndex] = {
-          idx: productsIndex,
-          name: specifications.toString(),
-          picUrl: '',
-          originPrice: 0.00,
-          exchangePrice: 0.00,
-          value: 0.00,
-          cost: 0.00,
-          quantity: 0,
-          properties
-        }
-        productsIndex++
-
-        index++
-        combination[n - 1] = index
-        for (var j = n - 1; j >= 0; j--) {
-          if (combination[j] >= specValues[j].length) {
-            combination[j] = 0
-            index = 0
-            if (j - 1 >= 0) {
-              combination[j - 1] = combination[j - 1] + 1
-            }
-          }
-        }
-        isContinue = false
-        for (var p = 0; p < n; p++) {
-          if (combination[p] !== 0) {
-            isContinue = true
-          }
-        }
-      } while (isContinue)
-
-      this.products = products
-    },
-    handleSpecificationAdd() {
-      const valueArr = this.specForm.value.replace(/,/ig,',').replace(/\s*/g,"").split(',') // 替换所有的中文逗号为英文逗号并去空格
-      valueArr.forEach(element => {
-        let index = this.specifications.length - 1
-        for (var i = 0; i < this.specifications.length; i++) {
-          const v = this.specifications[i]
-          if (v.specification === this.specForm.specification) {
-            if (v.value !== element) {
-              index = i
-            }
-          }
-        }
-        this.specifications.splice(index + 1, 0, {
-          specification: this.specForm.specification,
-          value: element
-        })
-        
-      });
-      this.specToProduct()
-      this.specVisiable = false
-    },
-    handleProductShow(row) {
-      this.productForm = Object.assign({}, row)
-      this.productVisiable = true
-    },
-    handleProductEdit() {
-      for (var i = 0; i < this.products.length; i++) {
-        const v = this.products[i]
-        if (v.idx === this.productForm.idx) {
-          this.products.splice(i, 1, this.productForm)
-          break
-        }
-      }
-      this.productVisiable = false
-    },
     updateItem() {
       this.$refs.addItem.validate((valid, items) => {
         if (valid) {
           this.addData.skuList = this.products
-          addGoods(this.addData).then(res => {
+          const { description, ...rest } = this.addData
+          addGoods({...rest, ...{description: encodeURI(description) }}).then(res => {
             if (res.code === 0) {
               this.$message({
                 message: this.addData.goodsId ? '修改成功!' : '添加成功!',
@@ -383,12 +184,9 @@ export default {
               type: 'warning'
             })
           }
-          
         }
       })
-    },
-
-    
+    }
   }
 }
 </script>
@@ -406,55 +204,5 @@ export default {
       left: 10px;
     }
   }
-  .flip-list-move {
-    transition: transform 0.5s;
-  }
-  .no-move {
-    transition: transform 0s;
-  }
-  .ghost {
-    opacity: 0.5;
-    background: #c8ebfb;
-  }
-  .list-group {
-    min-height: 120px;
-    padding: 20px;
-    border: 1px solid #EEE;
-  }
-  .list-empty {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    font-size: 14px;
-    color: #888;
-    height: 100px;
-  }
-  .list-group-item, .list-group-header {
-    padding: 0 16px;
-    height: 40px;
-    border-bottom: 1px solid #EBEEF5;
-    cursor: move;
-    display: flex;
-    align-items: center;
-    font-size: 14px;
-    color: #606266;
-    justify-content: space-between;
-    .f1 {
-      flex: 1;
-    }
-    .f2 {
-      flex: 2;
-    }
-    .tr {
-      text-align: right;
-    }
-  }
-  .list-group-header {
-    cursor: default;
-    background: #EBEEF5;
-  }
-  .list-group-item:hover {
-    background: #F3F6F9;
-  }
 }
 </style>

+ 241 - 0
src/views/business/goods/components/spec.vue

@@ -0,0 +1,241 @@
+<template>
+  <div>
+    <div v-if="multipleSpec">
+      <div style="margin-bottom: 16px">
+        <el-button :plain="true" type="primary" size="small" @click="handleSpecificationShow">添加规格</el-button>
+      </div>
+      <el-table :data="specifications">
+        <el-table-column property="specification" label="规格名"/>
+        <el-table-column property="value" label="规格值">
+          <template slot-scope="scope">
+            <el-tag type="primary">
+              {{ scope.row.value }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="操作" width="120">
+          <template slot-scope="scope">
+            <el-button type="danger" size="small" @click="handleSpecificationDelete(scope.row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <el-dialog :visible.sync="specVisiable" title="设置规格" :close-on-click-modal="false" width="400px">
+      <el-form ref="specForm" :model="specForm" label-width="80px">
+        <el-form-item label="规格名:" prop="specification">
+          <el-input v-model="specForm.specification"/>
+        </el-form-item>
+        <el-form-item label="规格值:" prop="value">
+          <el-input v-model="specForm.value"/>
+          <div class="tip">多个规格值请用逗号隔开</div>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="specVisiable = false">取消</el-button>
+        <el-button type="primary" @click="handleSpecificationAdd">确定</el-button>
+      </div>
+    </el-dialog>
+    <br>
+    <el-table v-if="multipleSpec" :data="products">
+      <el-table-column property="name" label="sku名称" />
+      <el-table-column property="picUrl" width="100" label="商品图片">
+        <template slot-scope="scope">
+          <img v-if="scope.row.picUrl" :src="IMG_URL+scope.row.picUrl" width="40">
+        </template>
+      </el-table-column>
+      <el-table-column property="value" label="价格"/>
+      <!-- <el-table-column property="originPrice" label="原兑换价格"/> -->
+      <el-table-column property="exchangePrice" label="兑换价格"/>
+      <el-table-column property="cost" label="成本"/>
+      <el-table-column property="quantity" label="库存数量"/>
+      <el-table-column align="center" label="操作" width="120">
+        <template slot-scope="scope">
+          <el-button type="primary" size="mini" @click="handleProductShow(scope.row)">设置</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <el-dialog :visible.sync="productVisiable" title="设置商品" :close-on-click-modal="false" width="400px">
+      <el-form ref="productForm" :model="productForm" label-width="100px">
+        <el-form-item label="sku名称:" prop="name">
+          <el-input v-model="productForm.name" />
+        </el-form-item>
+        <el-form-item label="价格:" prop="value">
+          <el-input-number v-model="productForm.value" />
+        </el-form-item>
+        <!-- <el-form-item label="原兑换价格:" prop="originPrice">
+          <el-input-number v-model="productForm.originPrice"/>
+        </el-form-item> -->
+        <el-form-item label="兑换价格:" prop="exchangePrice">
+          <el-input-number v-model="productForm.exchangePrice"/>
+        </el-form-item>
+        <el-form-item label="成本:" prop="cost">
+          <el-input-number v-model="productForm.cost"/>
+        </el-form-item>
+        <el-form-item label="库存数量:" prop="quantity">
+          <el-input-number v-model="productForm.quantity"/>
+        </el-form-item>
+        <el-form-item label="商品图片:" prop="picUrl">
+          <Upload :value="productForm.picUrl ? [{ fileName: productForm.picUrl }] : []" @input="productForm.picUrl = $event[0] ? $event[0].fileName : ''" :limit="1" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="productVisiable = false">取消</el-button>
+        <el-button type="primary" @click="handleProductEdit">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import Upload from '@/components/ImageUpload'
+export default {
+  name: 'Spec',
+  components: {
+    Upload
+  },
+  props: {
+    multiSku: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      specifications: [],
+      products: [],
+      specVisiable: false, // 规格弹窗
+      specForm: {}, // 规格暂存
+      productVisiable: false,
+      productForm: {},
+    }
+  },
+  computed: {
+    multipleSpec() {
+      return this.multiSku === 1
+    },
+  },
+  methods: {
+    handleSpecificationShow() {
+      this.specForm = {}
+      this.specVisiable = true
+    },
+    handleSpecificationDelete(row) {
+      const index = this.specifications.indexOf(row)
+      this.specifications.splice(index, 1)
+      this.specToProduct()
+    },
+    specToProduct() {
+      if (this.specifications.length === 0) {
+        return
+      }
+      // 根据specifications创建临时规格列表
+      var specValues = []
+      var spec = this.specifications[0].specification
+      var values = []
+      values.push(0)
+
+      for (var i = 1; i < this.specifications.length; i++) {
+        const aspec = this.specifications[i].specification
+
+        if (aspec === spec) {
+          values.push(i)
+        } else {
+          specValues.push(values)
+          spec = aspec
+          values = []
+          values.push(i)
+        }
+      }
+      specValues.push(values)
+
+      // 根据临时规格列表生产商品规格
+      // 算法基于 https://blog.csdn.net/tyhj_sf/article/details/53893125
+      var productsIndex = 0
+      var products = []
+      var combination = []
+      var n = specValues.length
+      for (var s = 0; s < n; s++) {
+        combination[s] = 0
+      }
+      var index = 0
+      var isContinue = false
+      do {
+        var specifications = []
+        var properties = ''
+        for (var x = 0; x < n; x++) {
+          var z = specValues[x][combination[x]]
+          specifications.push(this.specifications[z].value)
+          properties = `${properties ? (properties + ';') : ''}${this.specifications[z].specification}:${this.specifications[z].value}`
+        }
+        products[productsIndex] = {
+          idx: productsIndex,
+          name: specifications.toString(),
+          picUrl: '',
+          originPrice: 0.00,
+          exchangePrice: 0.00,
+          value: 0.00,
+          cost: 0.00,
+          quantity: 0,
+          properties
+        }
+        productsIndex++
+
+        index++
+        combination[n - 1] = index
+        for (var j = n - 1; j >= 0; j--) {
+          if (combination[j] >= specValues[j].length) {
+            combination[j] = 0
+            index = 0
+            if (j - 1 >= 0) {
+              combination[j - 1] = combination[j - 1] + 1
+            }
+          }
+        }
+        isContinue = false
+        for (var p = 0; p < n; p++) {
+          if (combination[p] !== 0) {
+            isContinue = true
+          }
+        }
+      } while (isContinue)
+
+      this.products = products
+    },
+    handleSpecificationAdd() {
+      const valueArr = this.specForm.value.replace(/,/ig,',').replace(/\s*/g,"").split(',') // 替换所有的中文逗号为英文逗号并去空格
+      valueArr.forEach(element => {
+        let index = this.specifications.length - 1
+        for (var i = 0; i < this.specifications.length; i++) {
+          const v = this.specifications[i]
+          if (v.specification === this.specForm.specification) {
+            if (v.value !== element) {
+              index = i
+            }
+          }
+        }
+        this.specifications.splice(index + 1, 0, {
+          specification: this.specForm.specification,
+          value: element
+        })
+        
+      });
+      this.specToProduct()
+      this.specVisiable = false
+    },
+    handleProductShow(row) {
+      this.productForm = Object.assign({}, row)
+      this.productVisiable = true
+    },
+    handleProductEdit() {
+      for (var i = 0; i < this.products.length; i++) {
+        const v = this.products[i]
+        if (v.idx === this.productForm.idx) {
+          this.products.splice(i, 1, this.productForm)
+          break
+        }
+      }
+      this.productVisiable = false
+    },
+  }
+}
+</script>

+ 11 - 7
src/views/business/goods/index.vue

@@ -59,24 +59,28 @@
         </template>
       </el-table-column>
       <el-table-column label="商品名称" prop="title" />
-      <el-table-column label="价格" prop="value" />
+      <el-table-column label="价格" prop="value">
+        <template slot-scope="{row}">¥{{ row.value }}</template>
+      </el-table-column>
+      <el-table-column label="成本" prop="cost">
+        <template slot-scope="{row}">¥{{ row.cost }}</template>
+      </el-table-column>
       <el-table-column label="兑换盲豆" prop="exchangePrice" />
       <el-table-column label="销量" prop="exchangedQty" />
       <el-table-column label="库存" prop="quantity" />
       <el-table-column label="状态" prop="status">
         <template slot-scope="{row}">
-          <el-tag v-if="row.status === 'on'" type="success">上架</el-tag>
-          <el-tag v-else-if="row.status === 'off'" type="info">下架</el-tag>
+          <el-tag :type="JSON.parse(row.status).value === 'on' ? 'success' : 'info'">{{ JSON.parse(row.status).desc }}</el-tag>
         </template>
       </el-table-column>
       <el-table-column label="排序" prop="sort" />
       <el-table-column fixed="right" align="right" label="操作" width="140">
         <template slot-scope="{row}">
           <!-- <el-button v-hasPermi="['business:goods:query']" type="text">查看</el-button> -->
-          <el-button v-hasPermi="['business:goods:edit']" type="text" @click="$router.push('/goods/edit?id=' + row.goodsId)">编辑</el-button>
-          <el-button v-if="row.status === 'off'" v-hasPermi="['business:goods:on']" type="text" @click="setStatus(row, 'on')">上架</el-button>
-          <el-button v-if="row.status === 'on'" v-hasPermi="['business:goods:off']" type="text" @click="setStatus(row, 'off')">下架</el-button>
-          <el-button v-if="row.status === 'off'" v-hasPermi="['business:coupon:remove']" class="del" type="text" @click="del(row)">删除</el-button>
+          <el-button v-if="JSON.parse(row.status).value === 'init'" v-hasPermi="['business:goods:edit']" type="text" @click="$router.push('/goods/edit?id=' + row.goodsId)">编辑</el-button>
+          <el-button v-if="JSON.parse(row.status).value === 'off' || JSON.parse(row.status).value === 'init'" v-hasPermi="['business:goods:on']" type="text" @click="setStatus(row, 'on')">上架</el-button>
+          <el-button v-if="JSON.parse(row.status).value === 'on'" v-hasPermi="['business:goods:off']" type="text" @click="setStatus(row, 'off')">下架</el-button>
+          <el-button v-if="JSON.parse(row.status).value === 'init'" v-hasPermi="['business:coupon:remove']" class="del" type="text" @click="del(row)">删除</el-button>
         </template>
       </el-table-column>
     </el-table>

+ 1 - 1
src/views/business/ticket/create.vue

@@ -562,7 +562,7 @@ export default {
           "&pageSize=" +
           this.pageParams.pageSize +
           "&",
-        { title: title }
+        { title: title, status: "on" }
       ).then((res) => {
         this.couponList = res.rows.map((item) => {
           return {

Some files were not shown because too many files changed in this diff