Преглед на файлове

服务号商城套餐维护

lighter преди 4 месеца
родител
ревизия
59dcfd2f86
променени са 2 файла, в които са добавени 449 реда и са изтрити 0 реда
  1. 34 0
      src/api/outpatient/wxmall-package.js
  2. 415 0
      src/views/clinic/wx-business/WxmallPackage.vue

+ 34 - 0
src/api/outpatient/wxmall-package.js

@@ -0,0 +1,34 @@
+import request from '../../utils/request'
+
+export function getPackagesByCondition(data) {
+  return request({
+    url: '/wxmallPackage/getPackagesByCondition',
+    method: 'post',
+    data
+  })
+}
+
+export function createNewPackage2(data) {
+  return request({
+    url: '/wxmallPackage/createNewPackage2',
+    method: 'post',
+    data
+  })
+}
+
+export function updatePackageState(data) {
+  return request({
+    url: '/wxmallPackage/updatePackageState',
+    method: 'post',
+    data
+  })
+}
+
+export function getPackageDetail(id) {
+  return request({
+    url: '/wxmallPackage/getPackageDetail',
+    method: 'get',
+    params: {id}
+  })
+}
+

+ 415 - 0
src/views/clinic/wx-business/WxmallPackage.vue

@@ -0,0 +1,415 @@
+<template>
+  <div class="layout_container wxmall-package">
+    <header class="round-header">
+      <span>上架时间:</span>
+      <CyDateRange />
+      <span class="ml-12">
+        套餐状态:
+      </span>
+      <el-select v-model="inquiry.state" clearable class="w-80">
+        <el-option label="已上架" value="ACTIVATED" />
+        <el-option label="已下架" value="DEACTIVATED" />
+      </el-select>
+      <el-divider direction="vertical" />
+      <el-button icon="Search" type="primary" @click="queryPackages">查询</el-button>
+      <el-button icon="Plus" color="green" @click="beforeAddPackage">上架</el-button>
+    </header>
+    <div class="layout_main layout_el-table">
+      <el-table :data="packageList" stripe>
+        <el-table-column prop="name" label="套餐名称" />
+        <el-table-column prop="price" label="套餐价格" />
+        <el-table-column prop="description" label="套餐描述" />
+        <el-table-column prop="createTime" label="创建时间" />
+        <el-table-column prop="createStaffName" label="创建人" />
+        <el-table-column label="状态">
+          <template #default="{row}">
+            <el-switch
+                v-model="row.state"
+                inline-prompt
+                style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
+                active-text="已上架"
+                inactive-text="已下架"
+                active-value="ACTIVATED"
+                inactive-value="DEACTIVATED"
+                @change="changePackageState(row)"
+            ></el-switch>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作">
+          <template #default="{row}">
+            <el-button
+                icon="View"
+                type="primary"
+                plain
+                @click="seePackageDetail(row.id)"
+            >
+              查看
+            </el-button>
+            <el-button
+                icon="Edit"
+                type="warning"
+                plain
+                @click="beforeEditPackage(row.id)"
+            >
+              编辑
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <el-drawer v-model="showCreation" :title="drawerTitle" size="50%">
+      <el-form :model="mainPackage" label-width="auto" :rules="packageMainRules">
+        <el-form-item label="套餐名称" prop="name">
+          <el-input v-model="mainPackage.name" maxlength="32" show-word-limit :disabled="disableEdit"/>
+        </el-form-item>
+        <el-form-item label="套餐描述">
+          <el-input
+              v-model="mainPackage.description"
+              maxlength="256"
+              show-word-limit
+              :disabled="disableEdit"
+              type="textarea"
+              :rows="3"
+          />
+        </el-form-item>
+        <el-form-item label="套餐图片" required prop="fileList">
+          <el-upload
+              :disabled="disableEdit"
+              class="avatar-uploader"
+              :show-file-list="false"
+              ref="uploadRef"
+              v-model:file-list="fileList"
+              :action="apiUrl + '/wxmallPackage/createNewPackage'"
+              :headers="header"
+              :data="creation"
+              :limit="1"
+              :on-change="handleSelectImage"
+              :on-exceed="handleExceed"
+              accept="image/jpeg,image/jpg,image/png"
+              :auto-upload="false"
+              :on-success="onSubmitSuccess"
+          >
+            <el-image v-if="imageUrl" fit="cover" :src="imageUrl" class="avatar-image" />
+            <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
+            <template #tip>
+              <div class="gray-text">
+                请选择小于 200Kb 的 jpg/png 格式的图片。
+              </div>
+            </template>
+          </el-upload>
+        </el-form-item>
+      </el-form>
+      <el-divider>
+        <el-tag>套餐明细</el-tag>
+      </el-divider>
+
+      <el-form
+          v-for="(item, index) in packageItemList"
+          :key="index"
+          :model="packageItemList[index]"
+          inline
+          :disabled="disableEdit"
+          label-width="auto"
+      >
+        <el-form-item label="名称" required>
+          <el-input v-model="item.hisName" readonly @click="displaySearchPanel(index)"/>
+        </el-form-item>
+        <el-form-item label="单价" required>
+          <el-input v-model="item.price" type="number" class="w-80" />
+        </el-form-item>
+        <el-form-item label="数量" required>
+          <el-input v-model.number="item.quantity" class="w-80" />
+        </el-form-item>
+        <el-form-item v-if="!disableEdit">
+          <el-button
+              v-if="index === packageItemList.length - 1"
+              icon="Plus"
+              type="success"
+              @click="addNewItemLine(index)"
+          >
+            添加
+          </el-button>
+          <el-button
+              icon="Minus"
+              type="danger"
+              @click="deleteItemLine(index)"
+          >
+            删除
+          </el-button>
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+        <div style="flex: auto" v-if="!disableEdit">
+          <el-button @click="showCreation = false" size="default">取消</el-button>
+          <el-button @click="submitUpload" size="default" type="primary">提交</el-button>
+        </div>
+      </template>
+    </el-drawer>
+    <Search
+        v-if="showSearch"
+        med-type="01"
+        target="SFXM"
+        title="收费项目查询"
+        @close="showSearch = false"
+        @click-item="handleClickSearchItem"
+    />
+  </div>
+</template>
+
+<script setup>
+import {
+  getPackagesByCondition,
+  getPackageDetail,
+  createNewPackage2,
+  updatePackageState
+} from "@/api/outpatient/wxmall-package.js";
+import useDateRange from "@/utils/cy-use/useDateRange";
+import {ElMessage, genFileId} from "element-plus";
+import {useUserStore} from "@/pinia/user-store";
+import env from "@/utils/setting";
+import Search from "@/components/search/Index.vue";
+
+const apiUrl = env.VITE_BASE_URL;
+
+const {CyDateRange, dateRange} = useDateRange({
+  shortcutsIndex: 2,
+  clearable: false,
+})
+
+const inquiry = reactive({
+  start: '',
+  end: '',
+  state: null
+})
+
+const packageList = ref([])
+function queryPackages() {
+  inquiry.start = dateRange.value.start
+  inquiry.end = dateRange.value.end
+  getPackagesByCondition(inquiry).then(data => {
+    packageList.value = data
+  })
+}
+
+function changePackageState(row) {
+  updatePackageState(row).then(data => {
+    ElMessage.success(data)
+  })
+}
+
+const packageMainRules = reactive({
+  name: [ { required: true, message: '请输入套餐名称', trigger: 'blur' } ],
+})
+
+const mode = ref('see')
+const drawerTitle = computed(() => {
+  if (mode.value === 'add') {
+    return '上架套餐'
+  }
+  if (mode.value === 'see') {
+    return '套餐详情'
+  }
+  return '编辑套餐'
+})
+const disableEdit = computed(() => {
+  return mode.value === 'see'
+})
+const showCreation = ref(false)
+const mainPackage = ref({})
+const uploadRef = ref()
+const fileList = ref([])
+const imageUrl = ref('');
+function beforeAddPackage() {
+  mode.value = 'add';
+  showCreation.value = true
+}
+function handleSelectImage({raw}) {
+  if (raw.type !== "image/jpeg" && raw.type !== "image/png") {
+    ElMessage.error("请选择 jpg/png 格式的图片!");
+    uploadRef.value.clearFiles();
+    return
+  }
+  if (raw.size / 1024 > 200) {
+    ElMessage.error("图片大小不能超过 200Kb!");
+    uploadRef.value.clearFiles();
+    return;
+  }
+  imageUrl.value = URL.createObjectURL(raw);
+}
+function handleExceed(files) {
+  uploadRef.value.clearFiles();
+  const file = files[0];
+  file.uid = genFileId();
+  uploadRef.value.handleStart(file);
+}
+
+const packageItemList = ref([{quantity: 1}])
+const showSearch = ref(false)
+const currentIndex = ref(0)
+function displaySearchPanel(index) {
+  currentIndex.value = index
+  showSearch.value = true
+}
+function handleClickSearchItem(val) {
+  packageItemList.value[currentIndex.value].hisCode = val.code
+  packageItemList.value[currentIndex.value].hisName = val.name
+  showSearch.value = false
+}
+function addNewItemLine(index) {
+  let item = packageItemList.value[index]
+  if (!isValidItem(item)) {
+    return
+  }
+  packageItemList.value.push({quantity: 1});
+}
+function deleteItemLine(index) {
+  packageItemList.value.splice(index, 1);
+}
+
+function isValidItem(item) {
+  if (!item.hisCode) {
+    ElMessage.error('请先填写项目名称')
+    return false
+  }
+  if (!item.price || item.price < 0) {
+    ElMessage.error('项目单价不能小于 0')
+    return false
+  }
+  if (!item.quantity || item.quantity < 1) {
+    ElMessage.error('项目数量不能小于 1,且必须为 整数')
+    return false
+  }
+  return true;
+}
+const addedItemCode = ref([])
+
+const header = {
+  token: useUserStore().getToken
+}
+const creation = ref({
+  mainPackageJson: null,
+  packageItemListJson: null
+})
+function submitUpload() {
+  addedItemCode.value = []
+  if (!mainPackage.value.name) {
+    ElMessage.error('套餐名称不能为空')
+    return
+  }
+  if (fileList.value.length === 0 && mode.value === 'add') {
+    ElMessage.error('套餐图片不能为空')
+    return
+  }
+  if (packageItemList.value.length === 0) {
+    ElMessage.error('套餐明细不能为空')
+    return
+  }
+  for (let i = 0; i < packageItemList.value.length; i++) {
+    let item = packageItemList.value[i]
+    if (addedItemCode.value.indexOf(item.hisCode) !== -1) {
+      ElMessage.error('请勿添加重复项')
+      return
+    }
+    addedItemCode.value.push(item.hisCode)
+    if (!isValidItem(item)) {
+      return
+    }
+  }
+  creation.value.mainPackageJson = JSON.stringify(mainPackage.value);
+  creation.value.packageItemListJson = JSON.stringify(packageItemList.value)
+  nextTick(() => {
+    if (fileList.value.length > 0) {
+      uploadRef.value.submit()
+    } else {
+      createNewPackage2(creation.value).then(res => {
+        onSubmitSuccess(res)
+      })
+    }
+  })
+}
+
+function resetFormData() {
+  mainPackage.value = {}
+  packageItemList.value = [{quantity: 1}]
+  creation.value = {
+    mainPackageJson: null,
+    packageItemListJson: null
+  }
+}
+
+function onSubmitSuccess(res) {
+  resetFormData()
+  nextTick(() => {
+    imageUrl.value = ''
+    uploadRef.value.clearFiles();
+    ElMessage.success('提交成功')
+    if (mode.value === 'add') {
+      packageList.value.push(res.data)
+    } else if (mode.value === 'edit') {
+      queryPackages()
+    }
+    showCreation.value = false
+  })
+}
+
+function seePackageDetail(id) {
+  getPackageDetail(id).then(res => {
+    mode.value = 'see';
+    mainPackage.value = res
+    packageItemList.value = res.items
+    imageUrl.value = res.thumbPath
+    showCreation.value = true
+  })
+}
+
+function beforeEditPackage(id) {
+  getPackageDetail(id).then(res => {
+    mode.value = 'edit';
+    mainPackage.value = res
+    packageItemList.value = res.items
+    imageUrl.value = res.thumbPath
+    showCreation.value = true
+  })
+}
+</script>
+
+<style lang="scss">
+.wxmall-package {
+  .ml-12 {
+    margin-left: 12px;
+  }
+  .w-80 {
+    width: 80px;
+  }
+  .gray-text {
+    color: gray;
+  }
+
+  .avatar-uploader {
+    .el-upload {
+      border: 1px dashed var(--el-border-color);
+      border-radius: 6px;
+      cursor: pointer;
+      position: relative;
+      overflow: hidden;
+      transition: var(--el-transition-duration-fast);
+    }
+    .el-upload:hover {
+      border-color: var(--el-color-primary);
+    }
+    .avatar-uploader-icon {
+      font-size: 28px;
+      color: #8c939d;
+      width: 100px;
+      height: 100px;
+      text-align: center;
+    }
+    .avatar-image {
+      width: 100px;
+      height: 100px;
+    }
+  }
+}
+
+</style>