Browse Source

一书一码

dusenyao 5 months ago
parent
commit
a2896687bf

+ 3 - 0
.env

@@ -6,3 +6,6 @@ VUE_APP_LearnWebSI = '/GCLSLearnWebSI/ServiceInterface'
 
 
 # BookWebSI
 # BookWebSI
 VUE_APP_BookWebSI = '/GCLSBookWebSI/ServiceInterface'
 VUE_APP_BookWebSI = '/GCLSBookWebSI/ServiceInterface'
+
+# BookServer
+VUE_APP_BookServer = '/GCLSBookServer/ServiceInterface'

+ 3 - 1
.vscode/settings.json

@@ -1 +1,3 @@
-{}
+{
+  "cSpell.words": ["GCLS", "oboc"]
+}

+ 26 - 0
src/api/list.js

@@ -102,3 +102,29 @@ export function PageQueryTaskLiveDetailList(data) {
     data
     data
   });
   });
 }
 }
+
+/**
+ * 分页查询一书一码列表
+ * @param { Object } data
+ */
+export function PageQueryOBOCList(data) {
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_BookServer,
+    params: getRequestParams('oboc-PageQueryOBOCList'),
+    data
+  });
+}
+
+/**
+ * 分页查询教材列表
+ * @param {Object} data
+ */
+export function PageQueryBookList(data) {
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_BookWebSI,
+    params: getRequestParams('book-book_manager-PageQueryBookList'),
+    data
+  });
+}

+ 40 - 0
src/api/oboc.js

@@ -0,0 +1,40 @@
+import { request, getRequestParams } from '@/utils/request';
+
+/**
+ * 创建一书一码
+ * @param {Object} data
+ */
+export function CreateOBOC(data) {
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_BookServer,
+    params: getRequestParams('oboc-CreateOBOC'),
+    data
+  });
+}
+
+/**
+ * 删除一书一码
+ * @param {Object} data
+ */
+export function DeleteOBOC(data) {
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_BookServer,
+    params: getRequestParams('oboc-DeleteOBOC'),
+    data
+  });
+}
+
+/**
+ * 废弃一书一码
+ * @param {Object} data
+ */
+export function DisableOBOC(data) {
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_BookServer,
+    params: getRequestParams('oboc-DisableOBOC'),
+    data
+  });
+}

+ 5 - 1
src/layouts/components/LayoutHeader.vue

@@ -38,7 +38,6 @@
 
 
 <script>
 <script>
 import UpdatePassword from './UpdatePassword.vue';
 import UpdatePassword from './UpdatePassword.vue';
-import { GetChildSysList_CanEnter_PC } from '@/api/app';
 
 
 export default {
 export default {
   name: 'LayoutHeader',
   name: 'LayoutHeader',
@@ -102,6 +101,11 @@ export default {
           isShow: is_inner
           isShow: is_inner
         },
         },
         {
         {
+          path: '/oboc',
+          name: '一书一码',
+          isShow: is_inner
+        },
+        {
           path: '/log',
           path: '/log',
           name: '操作日志',
           name: '操作日志',
           isShow: is_inner
           isShow: is_inner

+ 12 - 0
src/router/index.js

@@ -259,6 +259,18 @@ const routes = [
     ]
     ]
   },
   },
   {
   {
+    path: '/oboc',
+    component: Layout,
+    meta: { title: '一书一码', path: '/oboc' },
+    redirect: '/oboc/index',
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/oboc')
+      }
+    ]
+  },
+  {
     path: '/log',
     path: '/log',
     component: Layout,
     component: Layout,
     meta: { title: '操作日志' },
     meta: { title: '操作日志' },

+ 11 - 0
src/utils/index.js

@@ -0,0 +1,11 @@
+/**
+ * 复制到剪切板
+ * @param {string} id
+ */
+export async function useClipboard(id) {
+  const el = document.getElementById(id);
+  const value = el.value;
+  // 通过 navigator.clipboard 全局访问系统剪切板
+  // 使用 clipboard 的 writeText 方法实现复制
+  await navigator.clipboard.writeText(value);
+}

+ 103 - 0
src/views/oboc/CreateLink.vue

@@ -0,0 +1,103 @@
+<template>
+  <div>
+    <el-dialog width="480px" title="创建链接" :visible="visible" :before-close="close" :close-on-click-modal="false">
+      <el-form ref="form" :model="createForm" label-width="60px">
+        <el-form-item label="教材" prop="book_name">
+          <div class="select-book">
+            <el-input v-model="createForm.book_name" placeholder="请选择教材" disabled />
+            <el-button type="text" @click="selectBook">选择</el-button>
+          </div>
+        </el-form-item>
+        <el-form-item label="类型">
+          <el-select v-model="createForm.type" class="link-select">
+            <el-option label="试用" :value="0" />
+            <el-option label="一书一码" :value="1" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="有效期">
+          <el-select v-model="createForm.effective_day_count" class="link-select">
+            <el-option label="永久" :value="-1" />
+            <el-option
+              v-for="item in Array.from({ length: 90 }, (_, i) => i + 1)"
+              :key="item"
+              :label="`${item}天`"
+              :value="item"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+
+      <div slot="footer">
+        <el-button type="primary" @click="confirm">确定</el-button>
+        <el-button @click="close">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <SelectBook :visible="visibleSelectBook" @close="closeSelectBook" @confirm="confirmSelectBook" />
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'CreateLink'
+};
+</script>
+
+<script setup>
+import { ref, defineEmits } from 'vue';
+
+import SelectBook from './SelectBook.vue';
+
+defineProps({
+  visible: Boolean
+});
+
+const emits = defineEmits(['close', 'confirm']);
+
+let createForm = ref({
+  book_id: '',
+  book_name: '',
+  type: 1,
+  effective_day_count: 3
+});
+
+let visibleSelectBook = ref(false);
+function selectBook() {
+  visibleSelectBook.value = true;
+}
+
+function closeSelectBook() {
+  visibleSelectBook.value = false;
+}
+
+function confirmSelectBook(id, name) {
+  createForm.value.book_id = id;
+  createForm.value.book_name = name;
+  visibleSelectBook.value = false;
+}
+
+function close() {
+  emits('close');
+}
+
+function confirm() {
+  emits('confirm', createForm.value.book_id, createForm.value.type, createForm.value.effective_day_count);
+}
+</script>
+
+<style lang="scss" scoped>
+:deep .el-dialog__body {
+  padding-bottom: 0;
+}
+
+.select-book {
+  display: flex;
+  column-gap: 12px;
+}
+
+.el-form {
+  .link-select {
+    width: calc(100% - 43px);
+  }
+}
+</style>

+ 120 - 0
src/views/oboc/SelectBook.vue

@@ -0,0 +1,120 @@
+<template>
+  <el-dialog width="1000px" title="选择教材" :visible="visible" :before-close="close" :close-on-click-modal="false">
+    <div class="book-search">
+      <el-input v-model="name" placeholder="教材名称" @keyup.enter.native="pageQueryBookList" />
+      <el-button type="primary" @click="pageQueryBookList">搜索</el-button>
+    </div>
+    <CommonTable
+      :page-size="page_capacity"
+      :min-height="350"
+      :total="total_count"
+      :current-page="cur_page"
+      @prev-click="changePage($event, pageQueryBookList)"
+      @next-click="changePage($event, pageQueryBookList)"
+      @current-change="changePage($event, pageQueryBookList)"
+      @size-change="changePageSize($event, pageQueryBookList)"
+    >
+      <el-table :data="list" max-height="400px" highlight-current-row @current-change="handleCurrentChange">
+        <el-table-column label="序号" width="64">
+          <template slot-scope="{ $index }">
+            <span>{{ $index + 1 }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="name" label="教材名称" width="248" />
+        <el-table-column prop="label_name_list_desc" label="标签" width="124" />
+        <el-table-column prop="creator_name" label="创建者" width="160" />
+        <el-table-column prop="create_time" label="创建时间" width="180" />
+        <el-table-column prop="last_modifier_name" label="最近编辑" width="180" />
+        <el-table-column prop="last_modify_time" label="最近编辑时间" width="180" />
+        <el-table-column prop="description" label="简介" />
+      </el-table>
+    </CommonTable>
+    <div slot="footer">
+      <el-button type="primary" @click="confirm">确定</el-button>
+      <el-button @click="close">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  name: 'SelectBook'
+};
+</script>
+
+<script setup>
+import { ref, defineEmits } from 'vue';
+
+import { useList } from '@/utils/list';
+import { PageQueryBookList } from '@/api/list';
+import { MessageBox } from 'element-ui';
+
+import CommonTable from '@/components/common/CommonTable.vue';
+
+defineProps({
+  visible: Boolean
+});
+
+const emits = defineEmits(['confirm', 'close']);
+
+const { page_capacity, cur_page, total_count, list, changePage, changePageSize } = useList();
+
+let name = ref('');
+function pageQueryBookList() {
+  PageQueryBookList({
+    name: name.value,
+    org_id: '',
+    publish_status: 1,
+    creator_id: '',
+    sys_version_type: -1,
+    page_capacity: page_capacity.value,
+    cur_page: cur_page.value
+  }).then(({ book_list, total_count: total, cur_page: page }) => {
+    list.value = book_list;
+    total_count.value = total;
+    cur_page.value = page;
+  });
+}
+pageQueryBookList();
+
+let book = ref({
+  book_id: '',
+  book_name: ''
+});
+function handleCurrentChange(curRow) {
+  if (curRow === null) {
+    book.value = { book_id: '', book_name: '' };
+    return;
+  }
+
+  const { id, name } = curRow;
+  book.value = { book_id: id, book_name: name };
+}
+
+function confirm() {
+  if (!book.value.book_id) {
+    MessageBox.alert('请先选择教材', '提示', {
+      confirmButtonText: '确定',
+      type: 'warning'
+    });
+    return;
+  }
+  emits('confirm', book.value.book_id, book.value.book_name);
+}
+
+function close() {
+  emits('close');
+}
+</script>
+
+<style lang="scss" scoped>
+.book-search {
+  display: flex;
+  align-items: center;
+
+  .el-input {
+    width: 200px;
+    margin-right: 20px;
+  }
+}
+</style>

+ 177 - 0
src/views/oboc/index.vue

@@ -0,0 +1,177 @@
+<template>
+  <div class="oboc">
+    <div class="oboc-operation">
+      <el-button type="primary" @click="createLink">创建链接</el-button>
+    </div>
+
+    <CommonTable
+      :page-size="page_capacity"
+      :min-height="554"
+      :total="total_count"
+      :current-page="cur_page"
+      @prev-click="changePage($event, pageQueryOBOCList)"
+      @next-click="changePage($event, pageQueryOBOCList)"
+      @current-change="changePage($event, pageQueryOBOCList)"
+      @size-change="changePageSize($event, pageQueryOBOCList)"
+    >
+      <el-table :data="list">
+        <el-table-column label="类型" width="90" align="center">
+          <template slot-scope="{ row }">
+            <span>{{ row.type === 0 ? '试用' : '一书一码' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="book_name" label="教材" width="240" />
+        <el-table-column prop="identity_code" label="识别码" width="120" />
+        <el-table-column prop="creator_name" label="创建人" width="150" />
+        <el-table-column prop="create_time" label="创建时间" width="160" />
+        <el-table-column label="有效天数" width="100">
+          <template slot-scope="{ row }">
+            <span>{{ row.effective_day_count === -1 ? '永久' : `${row.effective_day_count}天` }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="到期剩余天数" width="140">
+          <template slot-scope="{ row }">
+            <span>{{ row.is_disabled === 'true' ? '已废弃' : formateDate(row.effective_end_date) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" fixed="right" width="200">
+          <template slot-scope="{ row }">
+            <span class="set-oboc operable" @click="copyLink(row.url)">复制链接</span>
+            <span class="set-oboc operable" @click="deleteOBOC(row.id)">删除</span>
+            <span v-if="row.is_disabled !== 'true'" class="set-oboc operable" @click="disableOBOC(row.id)">废弃</span>
+          </template>
+        </el-table-column>
+      </el-table>
+    </CommonTable>
+
+    <CreateLink :visible="visible" @close="closeCreateLink" @confirm="createOBOC" />
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'QuotaList'
+};
+</script>
+
+<script setup>
+import { ref } from 'vue';
+
+import { PageQueryOBOCList } from '@/api/list';
+import { CreateOBOC, DeleteOBOC, DisableOBOC } from '@/api/oboc';
+import { useList } from '@/utils/list';
+import { Message, MessageBox } from 'element-ui';
+
+import CommonTable from '@/components/common/CommonTable.vue';
+import CreateLink from './CreateLink.vue';
+
+const { page_capacity, cur_page, total_count, list, changePage, changePageSize } = useList();
+
+function pageQueryOBOCList() {
+  PageQueryOBOCList({
+    page_capacity: page_capacity.value,
+    cur_page: cur_page.value,
+    type: -1,
+    book_name: ''
+  }).then(({ oboc_list, total_count: total, cur_page: page }) => {
+    list.value = oboc_list;
+    total_count.value = total;
+    cur_page.value = page;
+  });
+}
+pageQueryOBOCList();
+
+let visible = ref(false);
+function createLink() {
+  visible.value = true;
+}
+
+function closeCreateLink() {
+  visible.value = false;
+}
+
+/**
+ * 创建一书一码
+ * @param {String} book_id
+ * @param {Number} type
+ * @param {Number} effective_day_count
+ */
+function createOBOC(book_id, type, effective_day_count) {
+  CreateOBOC({ book_id, type, effective_day_count }).then(() => {
+    visible.value = false;
+    pageQueryOBOCList();
+    Message.success(`创建一书一码成功`);
+  });
+}
+
+function copyLink(url) {
+  navigator.clipboard.writeText(url).then(() => {
+    Message.success(`复制链接成功`);
+  });
+}
+
+function deleteOBOC(id) {
+  MessageBox.confirm('是否删除该一书一码?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(() => {
+    DeleteOBOC({ id }).then(() => {
+      Message.success(`删除一书一码成功`);
+      pageQueryOBOCList();
+    });
+  });
+}
+
+function disableOBOC(id) {
+  MessageBox.confirm('是否废弃该一书一码?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  }).then(() => {
+    DisableOBOC({ id }).then(() => {
+      pageQueryOBOCList();
+      Message.success(`废弃一书一码成功`);
+    });
+  });
+}
+
+/**
+ * 将 20241221 转换为 2024年12月21日 格式
+ * @param {String} originalDate
+ */
+function formateDate(originalDate) {
+  const dateStr = originalDate.toString();
+  let year = dateStr.substring(0, 4);
+  let month = dateStr.substring(4, 6);
+  let day = dateStr.substring(6, 8);
+
+  return `${year}年${month}月${day}日`;
+}
+</script>
+
+<style lang="scss" scoped>
+@import '~@/styles/mixin';
+
+.oboc {
+  @include container;
+  @include dialog;
+
+  padding: 24px 0 46px;
+
+  &-operation {
+    display: flex;
+    align-items: center;
+  }
+
+  .el-table {
+    .set-oboc {
+      margin-right: 12px;
+    }
+
+    :deep th.el-table__cell {
+      color: #000;
+    }
+  }
+}
+</style>