Ver Fonte

扫码可见

xiongzhu há 4 anos atrás
pai
commit
e32e41c941

+ 5 - 4
src/main/java/com/izouma/nineth/repo/CollectionRepo.java

@@ -27,11 +27,12 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
     @Modifying
     @Query(value = "update collection_info c set c.on_shelf = ?2, c.salable = ?3, c.start_time = ?4, " +
             "c.schedule_sale = ?5, c.sort = ?6, c.detail = ?7, c.privileges = ?8, " +
-            "c.properties = ?9, c.model3d = ?10, c.max_count = ?11, c.count_id = ?12 where c.id = ?1",nativeQuery = true)
+            "c.properties = ?9, c.model3d = ?10, c.max_count = ?11, c.count_id = ?12, c.scan_code = ?13 " +
+            "where c.id = ?1", nativeQuery = true)
     @CacheEvict(value = {"collection", "recommend"}, allEntries = true)
     void update(@Nonnull Long id, boolean onShelf, boolean salable, LocalDateTime startTime,
                 boolean schedule, int sort, String detail, String privileges,
-                String properties, String model3d, int maxCount, String countId);
+                String properties, String model3d, int maxCount, String countId, boolean scanCode);
 
     @Cacheable("collection")
     Optional<Collection> findById(@Nonnull Long id);
@@ -90,9 +91,9 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
 
     @Transactional
     @Modifying
-    @Query("update Collection c set c.scheduleSale = false, c.startTime = null, c.onShelf = true, c.salable = true where c.id = ?1")
+    @Query("update Collection c set c.scheduleSale = false, c.startTime = null, c.onShelf = ?2, c.salable = true where c.id = ?1")
     @CacheEvict(value = "collection", key = "#id")
-    void scheduleOnShelf(Long id);
+    void scheduleOnShelf(Long id, boolean onShelf);
 
     @Query("select c.currentNumber from Collection c where c.id = ?1")
     Optional<Integer> getCurrentNumber(Long id);

+ 3 - 3
src/main/java/com/izouma/nineth/service/CollectionService.java

@@ -121,7 +121,7 @@ public class CollectionService {
                 record.getStartTime(), record.isScheduleSale(), record.getSort(),
                 record.getDetail(), JSON.toJSONString(record.getPrivileges()),
                 JSON.toJSONString(record.getProperties()), JSON.toJSONString(record.getModel3d()),
-                record.getMaxCount(), record.getCountId());
+                record.getMaxCount(), record.getCountId(), record.isScanCode());
         record = collectionRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
         onShelfTask(record);
         return record;
@@ -138,12 +138,12 @@ public class CollectionService {
             if (record.getStartTime().minusSeconds(2).isAfter(LocalDateTime.now())) {
                 Date date = Date.from(record.getStartTime().atZone(ZoneId.systemDefault()).toInstant());
                 ScheduledFuture<?> future = taskScheduler.schedule(() -> {
-                    collectionRepo.scheduleOnShelf(record.getId());
+                    collectionRepo.scheduleOnShelf(record.getId(), !record.isScanCode());
                     tasks.remove(record.getId());
                 }, date);
                 tasks.put(record.getId(), future);
             } else {
-                collectionRepo.scheduleOnShelf(record.getId());
+                collectionRepo.scheduleOnShelf(record.getId(), !record.isScanCode());
             }
         }
     }

+ 4 - 3
src/main/java/com/izouma/nineth/service/OrderService.java

@@ -101,6 +101,9 @@ public class OrderService {
                 throw new BusinessException("当前还未开售");
             }
         }
+        if (!collection.isSalable()) {
+            throw new BusinessException("该藏品当前不可购买");
+        }
         if (!collection.isOnShelf()) {
             if (!collection.isScanCode()) {
                 throw new BusinessException("藏品已下架");
@@ -109,9 +112,7 @@ public class OrderService {
         if (qty > collection.getStock()) {
             throw new BusinessException("库存不足");
         }
-        if (!collection.isSalable()) {
-            throw new BusinessException("该藏品当前不可购买");
-        }
+
 
         if (collection.getMaxCount() > 0) {
             int count;

+ 19 - 11
src/main/vue/src/components/CollectionSearch.vue

@@ -1,6 +1,6 @@
 <template>
-    <el-select v-model="collectionId" filterable :filter-method="filterCollection">
-        <el-option v-for="item in filterOptions" :label="item.name" :value="item.id" :key="item.id">
+    <el-select v-model="collectionId" filterable remote :remote-method="search" :loading="loading">
+        <el-option v-for="item in options" :label="item.name" :value="item.id" :key="item.id">
             <span style="float: left">{{ item.name }}</span>
             <span style="float: right; color: #8492a6; font-size: 13px">#{{ item.id }}</span>
         </el-option>
@@ -15,27 +15,38 @@ export default {
             .post(
                 '/collection/all',
                 {
-                    size: 10000,
                     sort: 'sort,desc;createdAt,desc',
                     query: { del: false, source: 'OFFICIAL', type: 'all' }
                 },
                 { body: 'json' }
             )
             .then(res => {
-                this.filterOptions = this.options = res.content;
+                this.options = res.content;
             });
     },
     data() {
         return {
             options: [],
-            filterOptions: [],
             collectionId: null,
-            selected: null
+            selected: null,
+            loading: false
         };
     },
     methods: {
-        filterCollection(val) {
-            this.filterOptions = this.options.filter(i => i.name.includes(val) || i.id == val);
+        search(query) {
+            this.$http
+                .post(
+                    '/collection/all',
+                    {
+                        sort: 'sort,desc;createdAt,desc',
+                        search: query,
+                        query: { del: false, source: 'OFFICIAL', type: 'all' }
+                    },
+                    { body: 'json' }
+                )
+                .then(res => {
+                    this.options = res.content;
+                });
         }
     },
     watch: {
@@ -45,9 +56,6 @@ export default {
                 this.selected = this.options.find(i => i.id === val);
                 this.$emit('select', this.selected);
             }
-            setTimeout(() => {
-                this.filterOptions = [...this.options];
-            }, 200);
         },
         value(val) {
             this.collectionId = val;

+ 247 - 60
src/main/vue/src/views/BlindBoxEdit.vue

@@ -67,6 +67,31 @@
                     <el-form-item>
                         <el-button size="mini" @click="addProperty"> 添加特性 </el-button>
                     </el-form-item>
+                    <el-form-item label="特权" prop="privileges" style="width: calc(100vw - 450px)">
+                        <el-table :data="privilegeOptions">
+                            <el-table-column prop="name" label="可选特权" width="150"></el-table-column>
+                            <el-table-column prop="description"></el-table-column>
+                            <el-table-column width="155" align="right">
+                                <template v-slot="{ row, $index }">
+                                    <el-button size="mini" v-if="!row.added" @click="addPrivilege(row, $index)">
+                                        添加
+                                    </el-button>
+                                    <el-button size="mini" v-if="!!row.added" plain @click="editPrivilege(row, $index)">
+                                        编辑
+                                    </el-button>
+                                    <el-button
+                                        size="mini"
+                                        v-if="!!row.added"
+                                        type="danger"
+                                        plain
+                                        @click="delPrivilege(row, $index)"
+                                    >
+                                        删除
+                                    </el-button>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                    </el-form-item>
                     <!-- <el-form-item prop="type" label="类型">
                         <el-select v-model="formData.type" clearable filterable placeholder="请选择">
                             <el-option
@@ -96,12 +121,9 @@
                         <el-input-number v-model="formData.total" disabled></el-input-number>
                     </el-form-item>
                     <el-form-item prop="items" label="包含作品" style="width: calc(100vw - 450px)">
-                        <el-table :data="blindBoxItems">
-                            <el-table-column
-                                prop="collectionId"
-                                label="名称"
-                                :formatter="collectionNameFormatter"
-                            ></el-table-column>
+                        <el-table :data="blindBoxItems" max-height="300px">
+                            <el-table-column prop="collectionId" label="ID"></el-table-column>
+                            <el-table-column prop="name" label="名称"></el-table-column>
                             <el-table-column prop="total" label="数量" width="100"></el-table-column>
                             <el-table-column prop="rare" label="稀有" width="100">
                                 <template v-slot="{ row }">
@@ -129,8 +151,17 @@
                     <!-- <el-form-item prop="likes" label="点赞">
                         <el-input-number v-model="formData.likes"></el-input-number>
                     </el-form-item> -->
+                    <el-form-item prop="scanCode" label="仅扫码可见">
+                        <el-radio v-model="formData.scanCode" :label="true">是</el-radio>
+                        <el-radio v-model="formData.scanCode" :label="false">否</el-radio>
+                    </el-form-item>
+                    <el-form-item prop="onShelf" label="上架" v-if="!formData.scanCode">
+                        <el-radio v-model="formData.onShelf" :label="true">是</el-radio>
+                        <el-radio v-model="formData.onShelf" :label="false">否</el-radio>
+                    </el-form-item>
                     <el-form-item prop="startTime" label="定时发布">
-                        <el-switch v-model="formData.scheduleSale" active-text="是" inactive-text="否"></el-switch>
+                        <el-radio v-model="formData.scheduleSale" :label="true">是</el-radio>
+                        <el-radio v-model="formData.scheduleSale" :label="false">否</el-radio>
                         <div style="margin-top: 10px" v-if="formData.scheduleSale">
                             <el-date-picker
                                 v-model="formData.startTime"
@@ -140,11 +171,15 @@
                             ></el-date-picker>
                         </div>
                     </el-form-item>
-                    <el-form-item prop="onShelf" label="上架" v-if="!formData.scheduleSale">
-                        <el-switch v-model="formData.onShelf" active-text="上架" inactive-text="下架"></el-switch>
-                    </el-form-item>
-                    <el-form-item prop="salable" label="可售">
-                        <el-switch v-model="formData.salable" active-text="可销售" inactive-text="仅展示"></el-switch>
+                    <el-form-item
+                        prop="salable"
+                        label="可售"
+                        v-if="
+                            formData.onShelf === true || (formData.scanCode === true && formData.scheduleSale === false)
+                        "
+                    >
+                        <el-radio v-model="formData.salable" :label="true">是</el-radio>
+                        <el-radio v-model="formData.salable" :label="false">仅展示</el-radio>
                     </el-form-item>
                     <el-form-item prop="maxCount" label="限购">
                         <el-input-number v-model="formData.maxCount"></el-input-number>
@@ -175,12 +210,7 @@
                 :rules="addItemFormRules"
             >
                 <el-form-item prop="collectionId" label="作品">
-                    <el-select v-model="addItemForm.collectionId">
-                        <el-option v-for="item in collections" :label="item.name" :value="item.id" :key="item.id">
-                            <span style="float: left">{{ item.name }}</span>
-                            <span style="float: right; color: #8492a6; font-size: 13px">#{{ item.id }}</span>
-                        </el-option>
-                    </el-select>
+                    <collection-search v-model="addItemForm.collectionId" @select="selectItem"> </collection-search>
                 </el-form-item>
                 <el-form-item prop="total" label="数量">
                     <el-input-number v-model="addItemForm.total" :min="1" :max="addItemForm.max || 0"></el-input-number>
@@ -194,44 +224,131 @@
                 <el-button size="mini" @click="onAddItem" type="primary">确定</el-button>
             </div>
         </el-dialog>
+
+        <el-dialog :visible.sync="showPrivilegeEditDialog" width="600px" :title="privilegeForm.name">
+            <el-form
+                ref="privilegeForm"
+                :model="privilegeForm"
+                label-position="right"
+                label-width="80px"
+                :rules="privelegeRules"
+            >
+                <el-form-item
+                    prop="detail"
+                    label="详细内容"
+                    v-if="privilegeForm.type === 'text' || privilegeForm.type === 'exchange'"
+                >
+                    <el-input type="textarea" :autosize="{ minRows: 3 }" v-model="privilegeForm.detail"></el-input>
+                </el-form-item>
+                <el-form-item prop="detail" label="二维码" v-if="privilegeForm.type === 'qrcode'">
+                    <single-upload v-model="privilegeForm.detail"></single-upload>
+                </el-form-item>
+                <el-form-item
+                    prop="remark"
+                    label="说明"
+                    v-if="privilegeForm.type === 'qrcode' || privilegeForm.type === 'code'"
+                >
+                    <el-input type="textarea" :autosize="{ minRows: 3 }" v-model="privilegeForm.remark"></el-input>
+                </el-form-item>
+            </el-form>
+            <div slot="footer">
+                <el-button @click="showPrivilegeEditDialog = false">取消</el-button>
+                <el-button type="primary" @click="savePrivilege">保存</el-button>
+            </div>
+        </el-dialog>
     </div>
 </template>
 <script>
 import resolveUrl from 'resolve-url';
+import ModelUpload from '../components/ModelUpload.vue';
+import { format, parse, isBefore } from 'date-fns';
 export default {
     name: 'BlindBoxEdit',
     created() {
-        if (this.$route.query.id) {
-            this.$http
-                .get('collection/get/' + this.$route.query.id)
-                .then(res => {
-                    res.properties = res.properties || [];
-                    this.formData = res;
-                })
-                .catch(e => {
-                    console.log(e);
-                    this.$message.error(e.error);
-                });
+        // if (this.$route.query.id) {
+        //     this.$http
+        //         .get('collection/get/' + this.$route.query.id)
+        //         .then(res => {
+        //             res.properties = res.properties || [];
+        //             this.formData = res;
+        //         })
+        //         .catch(e => {
+        //             console.log(e);
+        //             this.$message.error(e.error);
+        //         });
+        //     this.$http
+        //         .post(
+        //             '/blindBoxItem/all',
+        //             { query: { blindBoxId: this.$route.query.id }, size: 10000 },
+        //             { body: 'json' }
+        //         )
+        //         .then(res => {
+        //             this.blindBoxItems = res.content;
+        //         });
+        // }
+        // this.$http
+        //     .post(
+        //         '/collection/all',
+        //         { query: { del: false, source: 'OFFICIAL' }, size: 10000, sort: 'sort,desc;createdAt,desc' },
+        //         { body: 'json' }
+        //     )
+        //     .then(res => {
+        //         this.collections = res.content;
+        //     });
+
+        Promise.all([
+            new Promise((resolve, reject) => {
+                if (this.$route.query.id) {
+                    return this.$http
+                        .get('collection/get/' + this.$route.query.id)
+                        .then(res => {
+                            res.properties = res.properties || [];
+                            res.privileges = res.privileges || [];
+                            this.formData = res;
+                            resolve();
+                        })
+                        .catch(e => {
+                            console.log(e);
+                            this.$message.error(e.error);
+                            resolve();
+                        });
+                }
+                return resolve();
+            }),
             this.$http
-                .post(
-                    '/blindBoxItem/all',
-                    { query: { blindBoxId: this.$route.query.id }, size: 10000 },
-                    { body: 'json' }
-                )
+                .post('/privilegeOption/all', { size: 10000, query: { del: false } }, { body: 'json' })
                 .then(res => {
-                    this.blindBoxItems = res.content;
-                });
-        }
-        this.$http
-            .post(
-                '/collection/all',
-                { query: { del: false, source: 'OFFICIAL' }, size: 10000, sort: 'sort,desc;createdAt,desc' },
-                { body: 'json' }
-            )
-            .then(res => {
-                this.collections = res.content;
+                    this.privilegeOptions = res.content;
+                    return Promise.resolve();
+                }),
+            new Promise((resolve, reject) => {
+                if (this.$route.query.id) {
+                    this.$http
+                        .post(
+                            '/blindBoxItem/all',
+                            { query: { blindBoxId: this.$route.query.id }, size: 10000 },
+                            { body: 'json' }
+                        )
+                        .then(res => {
+                            this.blindBoxItems = res.content;
+                            resolve();
+                        })
+                        .catch(e => {
+                            resolve();
+                        });
+                } else {
+                    resolve();
+                }
+            })
+        ]).then(() => {
+            console.log(this.formData, this.privilegeOptions);
+            this.formData.privileges.forEach(p => {
+                let idx = this.privilegeOptions.findIndex(i => i.name === p.name);
+                if (idx > -1) {
+                    this.$set(this.privilegeOptions[idx], 'added', true);
+                }
             });
-
+        });
         // this.formData = {
         //     name: 'OASISPUNK绿洲朋克',
         //     pic: ['https://awesomeadmin.oss-cn-hangzhou.aliyuncs.com/image/2021-10-21-16-44-52kZqxuwhH.gif'],
@@ -279,7 +396,7 @@ export default {
         return {
             saving: false,
             formData: {
-                onShelf: true,
+                onShelf: false,
                 salable: true,
                 properties: [],
                 type: 'BLIND_BOX',
@@ -287,8 +404,10 @@ export default {
                 pic: [{}],
                 scheduleSale: true,
                 privileges: [],
+                sort: 0,
                 maxCount: 0,
-                countId: null
+                countId: null,
+                scanCode: false
             },
             rules: {
                 name: [
@@ -412,12 +531,19 @@ export default {
                 startTime: [
                     {
                         validator: (rule, value, callback) => {
-                            if (this.formData.scheduleSale === true && !value) {
-                                callback(new Error('请填写开售时间'));
-                                return;
+                            if (this.formData.scheduleSale) {
+                                if (!value) {
+                                    callback(new Error('请填写发布时间'));
+                                } else if (isBefore(parse(value, 'yyyy-MM-dd HH:mm:ss', new Date()), new Date())) {
+                                    callback(new Error('发布时间不能小于当前时间'));
+                                } else {
+                                    callback();
+                                }
+                            } else {
+                                callback();
                             }
-                            callback();
-                        }
+                        },
+                        trigger: 'blur'
                     }
                 ],
                 items: [
@@ -452,7 +578,14 @@ export default {
                 total: [{ required: true, message: '请输入数量' }]
             },
             cateogories: ['勋章', '收藏品', '数字艺术', '门票', '游戏', '音乐', '使用', '其他'],
-            customUrl: resolveUrl(this.$baseUrl, 'upload/3dModel')
+            customUrl: resolveUrl(this.$baseUrl, 'upload/3dModel'),
+            privilegeOptions: [],
+            showPrivilegeEditDialog: false,
+            privilegeForm: {},
+            privelegeRules: {
+                detail: [{ required: true, message: '请填写内容' }],
+                remark: [{ required: true, message: '请填写说明' }]
+            }
         };
     },
     methods: {
@@ -546,22 +679,76 @@ export default {
         },
         removeItem(i) {
             this.blindBoxItems.splice(i, 1);
+        },
+        addPrivilege(row, i) {
+            this.privilegeForm = { ...row };
+            this.showPrivilegeEditDialog = true;
+            if (this.$refs.privilegeForm) {
+                this.$nextTick(() => {
+                    this.$refs.privilegeForm.clearValidate();
+                });
+            }
+        },
+        editPrivilege(row, i) {
+            this.privilegeForm = { ...(this.formData.privileges.find(e => e.name === row.name) || {}) };
+            this.showPrivilegeEditDialog = true;
+            if (this.$refs.privilegeForm) {
+                this.$nextTick(() => {
+                    this.$refs.privilegeForm.clearValidate();
+                });
+            }
+        },
+        delPrivilege(row, i) {
+            let idx = this.formData.privileges.findIndex(e => e.name === row.name);
+            if (idx > -1) {
+                this.formData.privileges.splice(idx, 1);
+            }
+            this.$set(this.privilegeOptions[i], 'added', false);
+        },
+        savePrivilege() {
+            this.$refs.privilegeForm
+                .validate()
+                .then(() => {
+                    let i = this.formData.privileges.findIndex(e => e.name === this.privilegeForm.name);
+                    if (i > -1) {
+                        this.$set(this.formData.privileges, i, { ...this.privilegeForm });
+                    } else {
+                        this.formData.privileges.push({ ...this.privilegeForm });
+                    }
+                    let ii = this.privilegeOptions.findIndex(i => i.name === this.privilegeForm.name);
+                    console.log(ii);
+                    this.$set(this.privilegeOptions[ii], 'added', true);
+                    this.showPrivilegeEditDialog = false;
+                })
+                .catch(e => {
+                    console.log(e);
+                });
+        },
+        selectItem(item) {
+            this.$set(this.addItemForm, 'max', item.stock || 0);
+            this.$set(this.addItemForm, 'name', item.name);
         }
     },
     watch: {
-        'addItemForm.collectionId'(val) {
-            if (val) {
-                this.$set(this.addItemForm, 'max', (this.collections.find(i => i.id === val) || {}).stock || 0);
-            }
-        },
         blindBoxItems() {
             this.$set(
                 this.formData,
                 'total',
                 this.blindBoxItems.map(i => i.total).reduce((a, b) => a + b, 0)
             );
+        },
+        'formData.scanCode'(val) {
+            if (val === true) {
+                this.$set(this.formData, 'onShelf', false);
+            }
         }
     }
 };
 </script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.inline-wrapper {
+    .el-form-item {
+        display: inline-block;
+    }
+}
+</style>

+ 101 - 41
src/main/vue/src/views/CollectionEdit.vue

@@ -11,10 +11,9 @@
                     :model="formData"
                     :rules="rules"
                     ref="form"
-                    label-width="94px"
+                    label-width="120px"
                     label-position="right"
                     size="small"
-                    style="max-width: 500px"
                 >
                     <el-form-item prop="name" label="名称">
                         <el-input v-model="formData.name" :disabled="!canEdit"></el-input>
@@ -40,18 +39,25 @@
                         ></model-upload>
                         <div class="tip">请将FBX文件与贴图打包成zip压缩包上传</div>
                     </el-form-item>
-                    <el-form-item prop="minterId" label="铸造者">
-                        <minter-select
-                            v-model="formData.minterId"
-                            @detail="onMinterDetail"
-                            :disabled="!canEdit"
-                        ></minter-select>
-                    </el-form-item>
-                    <el-form-item prop="category" label="分类">
-                        <el-select v-model="formData.category" :disabled="!canEdit">
-                            <el-option v-for="item in cateogories" :label="item" :value="item" :key="item"></el-option>
-                        </el-select>
-                    </el-form-item>
+                    <div class="inline-wrapper">
+                        <el-form-item prop="minterId" label="铸造者">
+                            <minter-select
+                                v-model="formData.minterId"
+                                @detail="onMinterDetail"
+                                :disabled="!canEdit"
+                            ></minter-select>
+                        </el-form-item>
+                        <el-form-item prop="category" label="分类">
+                            <el-select v-model="formData.category" :disabled="!canEdit">
+                                <el-option
+                                    v-for="item in cateogories"
+                                    :label="item"
+                                    :value="item"
+                                    :key="item"
+                                ></el-option>
+                            </el-select>
+                        </el-form-item>
+                    </div>
                     <el-form-item prop="detail" label="详情" style="width: calc(100vw - 450px)">
                         <rich-text v-model="formData.detail"></rich-text>
                     </el-form-item>
@@ -126,32 +132,50 @@
                             </el-option>
                         </el-select>
                     </el-form-item> -->
-                    <el-form-item prop="price" label="价格">
-                        <el-input-number type="number" v-model="formData.price" :disabled="!canEdit"></el-input-number>
-                    </el-form-item>
-                    <el-form-item prop="price" label="原价">
-                        <el-input-number
-                            type="number"
-                            v-model="formData.originalPrice"
-                            :disabled="!canEdit"
-                        ></el-input-number>
-                    </el-form-item>
-                    <el-form-item prop="royalties" label="版税(%)">
-                        <el-input-number v-model="formData.royalties" :min="0" :max="99" :disabled="!canEdit">
-                        </el-input-number>
-                    </el-form-item>
-                    <el-form-item prop="serviceCharge" label="手续费(%)">
-                        <el-input-number v-model="formData.serviceCharge" :min="0" :max="99" :disabled="!canEdit">
-                        </el-input-number>
-                    </el-form-item>
+                    <div class="inline-wrapper">
+                        <el-form-item prop="price" label="价格">
+                            <el-input-number
+                                type="number"
+                                v-model="formData.price"
+                                :disabled="!canEdit"
+                            ></el-input-number>
+                        </el-form-item>
+                        <el-form-item prop="price" label="原价">
+                            <el-input-number
+                                type="number"
+                                v-model="formData.originalPrice"
+                                :disabled="!canEdit"
+                            ></el-input-number>
+                        </el-form-item>
+                    </div>
+                    <div class="inline-wrapper">
+                        <el-form-item prop="royalties" label="版税(%)">
+                            <el-input-number v-model="formData.royalties" :min="0" :max="99" :disabled="!canEdit">
+                            </el-input-number>
+                        </el-form-item>
+                        <el-form-item prop="serviceCharge" label="手续费(%)">
+                            <el-input-number v-model="formData.serviceCharge" :min="0" :max="99" :disabled="!canEdit">
+                            </el-input-number>
+                        </el-form-item>
+                    </div>
                     <el-form-item prop="total" label="发行数量">
                         <el-input-number v-model="formData.total" :disabled="!canEdit"></el-input-number>
                     </el-form-item>
+
                     <!-- <el-form-item prop="likes" label="点赞">
                         <el-input-number v-model="formData.likes"></el-input-number>
                     </el-form-item> -->
+                    <el-form-item prop="scanCode" label="仅扫码可见">
+                        <el-radio v-model="formData.scanCode" :label="true">是</el-radio>
+                        <el-radio v-model="formData.scanCode" :label="false">否</el-radio>
+                    </el-form-item>
+                    <el-form-item prop="onShelf" label="上架" v-if="!formData.scanCode">
+                        <el-radio v-model="formData.onShelf" :label="true">是</el-radio>
+                        <el-radio v-model="formData.onShelf" :label="false">否</el-radio>
+                    </el-form-item>
                     <el-form-item prop="startTime" label="定时发布">
-                        <el-switch v-model="formData.scheduleSale" active-text="是" inactive-text="否"></el-switch>
+                        <el-radio v-model="formData.scheduleSale" :label="true">是</el-radio>
+                        <el-radio v-model="formData.scheduleSale" :label="false">否</el-radio>
                         <div style="margin-top: 10px" v-if="formData.scheduleSale">
                             <el-date-picker
                                 v-model="formData.startTime"
@@ -161,11 +185,15 @@
                             ></el-date-picker>
                         </div>
                     </el-form-item>
-                    <el-form-item prop="onShelf" label="上架" v-if="!formData.scheduleSale">
-                        <el-switch v-model="formData.onShelf" active-text="上架" inactive-text="下架"></el-switch>
-                    </el-form-item>
-                    <el-form-item prop="salable" label="可售">
-                        <el-switch v-model="formData.salable" active-text="可销售" inactive-text="仅展示"></el-switch>
+                    <el-form-item
+                        prop="salable"
+                        label="可售"
+                        v-if="
+                            formData.onShelf === true || (formData.scanCode === true && formData.scheduleSale === false)
+                        "
+                    >
+                        <el-radio v-model="formData.salable" :label="true">是</el-radio>
+                        <el-radio v-model="formData.salable" :label="false">仅展示</el-radio>
                     </el-form-item>
                     <el-form-item prop="sort" label="排序">
                         <el-input-number v-model="formData.sort" :min="0"></el-input-number>
@@ -226,6 +254,7 @@
 <script>
 import resolveUrl from 'resolve-url';
 import ModelUpload from '../components/ModelUpload.vue';
+import { format, parse, isBefore } from 'date-fns';
 export default {
     name: 'CollectionEdit',
     components: { ModelUpload },
@@ -274,7 +303,7 @@ export default {
         return {
             saving: false,
             formData: {
-                onShelf: true,
+                onShelf: false,
                 salable: true,
                 properties: [],
                 type: 'DEFAULT',
@@ -285,7 +314,8 @@ export default {
                 privileges: [],
                 maxCount: 0,
                 countId: null,
-                canResale: true
+                canResale: true,
+                scanCode: false
             },
             rules: {
                 name: [
@@ -408,7 +438,25 @@ export default {
                 ],
                 category: [{ required: true, message: '请填写分类' }],
                 royalties: [{ required: true, message: '请填写版税' }],
-                serviceCharge: [{ required: true, message: '请填手续费' }]
+                serviceCharge: [{ required: true, message: '请填手续费' }],
+                startTime: [
+                    {
+                        validator: (rule, value, callback) => {
+                            if (this.formData.scheduleSale) {
+                                if (!value) {
+                                    callback(new Error('请填写发布时间'));
+                                } else if (isBefore(parse(value, 'yyyy-MM-dd HH:mm:ss', new Date()), new Date())) {
+                                    callback(new Error('发布时间不能小于当前时间'));
+                                } else {
+                                    callback();
+                                }
+                            } else {
+                                callback();
+                            }
+                        },
+                        trigger: 'blur'
+                    }
+                ]
             },
             typeOptions: [
                 { label: '默认', value: 'DEFAULT' },
@@ -532,6 +580,13 @@ export default {
                     console.log(e);
                 });
         }
+    },
+    watch: {
+        'formData.scanCode'(val) {
+            if (val === true) {
+                this.$set(this.formData, 'onShelf', false);
+            }
+        }
     }
 };
 </script>
@@ -558,4 +613,9 @@ export default {
     color: @text3;
     margin-top: 5px;
 }
+.inline-wrapper {
+    .el-form-item {
+        display: inline-block;
+    }
+}
 </style>