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

消息通知和学习中心前端页面搭建

songxy преди 1 година
родител
ревизия
edf165d7e1

+ 16 - 0
client/src/router/modules/remaining.ts

@@ -88,6 +88,22 @@ const remainingRouter: AppRouteRecordRaw[] = [
           affix: true
         }
       },
+      {
+        path: 'noticeAndLearn',
+        component: () => import('@/views/OaSystem/noticeAndLearn/index.vue'),
+        name: 'noticeAndLearn',
+        meta: {
+          title: '通知公告'
+        }
+      },
+      {
+        path: 'noticeAndLearnEditor',
+        component: () => import('@/views/OaSystem/noticeAndLearn/editor.vue'),
+        name: 'noticeAndLearnEditor',
+        meta: {
+          title: '通知公告'
+        }
+      },
       {
         path: 'mainOfficeCenter',
         component: () => import('@/views/OaSystem/officeCenter/main/index.vue'),

+ 269 - 0
client/src/views/OaSystem/noticeAndLearn/editor.vue

@@ -0,0 +1,269 @@
+<template>
+  <div class="newsSettingBox">
+    <el-form ref="ruleFormRef" :model="formData" :rules="rules" label-width="120px">
+      <el-form-item label="标题" prop="title">
+        <el-input v-model="formData.title" placeholder="请输入标题" />
+      </el-form-item>
+      <el-form-item label="简介" prop="description">
+        <el-input
+          type="textarea"
+          :rows="4"
+          v-model="formData.description"
+          placeholder="请输入文章简介"
+        />
+      </el-form-item>
+      <el-form-item label="附件" prop="imgurl">
+        <div class="uploadFileBox">
+          <el-input v-model="formData.imgurl" placeholder="请上传文件" />
+          <span>
+            <el-button type="primary" @click="uploadHandle">开始上传</el-button>
+            <input type="file" style="display: none" ref="fileRef" @change="fileChangeHandle" />
+          </span>
+        </div>
+      </el-form-item>
+      <el-form-item label="内容">
+        <Tinymce v-model="formData.content" width="100%" height="800px" />
+      </el-form-item>
+    </el-form>
+    <div class="btnGroup" style="text-align: right">
+      <span v-if="formData.isPub === 0">
+        <el-button type="primary" @click="onSubmit(ruleFormRef, 1)">立即发布</el-button>
+        <el-button type="primary" @click="onSubmit(ruleFormRef, 0)">暂存</el-button>
+      </span>
+      <span v-else>
+        <el-button type="primary" @click="onSubmit(ruleFormRef)">保存</el-button>
+      </span>
+      <el-button @click="router.back()">取消</el-button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { useRoute } from 'vue-router'
+import axios from 'axios'
+import moment from 'moment'
+import { Base64 } from 'js-base64'
+import request from '@/config/axios'
+import { ElMessage, ElMessageBox, Action, FormRules, FormInstance } from 'element-plus'
+import router from '@/router'
+
+const initFormData: any = {
+  id: null,
+  sid: 1,
+  title: '',
+  description: '',
+  imgurl: '',
+  happenTime: '',
+  adddate: '',
+  sort: 0,
+  status: 1, //0 不显示 1 显示
+  isTop: 0,
+  isSyncSite: 1,
+  content: '',
+  seoTitle: '',
+  seoKeywords: '',
+  seoDesc: '',
+  isPub: 0
+}
+const eTypeRef = ref<string>('add')
+const formData = ref(initFormData)
+const ruleFormRef = ref<FormInstance>()
+const rules = reactive<
+  FormRules<{
+    title: string
+    description: string
+    imgurl: string
+  }>
+>({
+  title: {
+    required: true,
+    message: '标题不能为空! ',
+    trigger: 'change'
+  },
+  description: {
+    required: true,
+    message: '简介不能为空! ',
+    trigger: 'change'
+  },
+  imgurl: {
+    required: true,
+    message: '图片不能为空! ',
+    trigger: 'change'
+  }
+})
+//同步官网Switch组件
+function beforeChangeHandle(): boolean | Promise<boolean> {
+  const val: number = formData.value.isSyncSite
+  if (val === 0) return true
+  return new Promise((resolve, reject) => {
+    ElMessageBox.alert('确定取消同步到公司官网?', '', {
+      callback: (action: Action) => {
+        if (action === 'confirm') {
+          resolve(true)
+        } else {
+          reject(false)
+        }
+      }
+    })
+  })
+}
+function restForm() {
+  formData.value = initFormData
+}
+//保存数据接口逻辑
+function onSubmit(formEl: FormInstance | undefined, num?: number): void {
+  if (!formEl) return
+  formEl.validate((valid, fields: any) => {
+    if (valid) {
+      let urlApi: string = ''
+
+      const sendData = {
+        ...formData.value
+      }
+      if (eTypeRef.value === 'add') {
+        urlApi = '/adm/article/add'
+      } else {
+        urlApi = '/adm/article/update'
+      }
+
+      if (formData.value['isPub'] === 0 && num === 1) {
+        sendData['adddate'] = moment().format('YYYY-MM-DD HH:mm:ss')
+        sendData['isPub'] = 1
+      }
+      request.post({ url: urlApi, data: sendData }).then((result) => {
+        if (result) {
+          ElMessage({
+            showClose: true,
+            message: '保存成功.',
+            type: 'success'
+          })
+          if (
+            formData.value['isPub'] === 0 &&
+            sendData['isPub'] === 1 &&
+            formData.value.isSyncSite === 1
+          ) {
+            syncSiteAjax(formData.value)
+          }
+          if (num !== 0) {
+            router.back()
+          }
+        }
+      })
+    } else {
+      const keys = Object.keys(fields)
+      ElMessage.error(fields[keys[0]][0]['message'])
+    }
+  })
+}
+//同步官网接口——需要代理转发
+const syncSiteAjax = async (data): Promise<void> => {
+  const header = {
+    token: 'L7grJk5JnyWhsnX0D5OZ8sero5PiZkk7'
+  }
+  const body = {
+    sid: data.sid,
+    title: data.title,
+    description: data.description,
+    imgurl: data.imgurl,
+    adddate: data.adddate,
+    status: data.status,
+    content: data.content,
+    seo_title: data.seoTitle,
+    seo_keywords: data.seoKeywords,
+    seo_desc: data.seoDesc
+  }
+  const sendData = {
+    _encrypted_data: Base64.encode(JSON.stringify(body))
+  }
+  const result = await axios({
+    url: '/widewebApi/api/Article/pushNews',
+    method: 'POST',
+    data: sendData,
+    headers: header
+  })
+  if (result && result['data']) {
+    ElMessage({
+      showClose: true,
+      message: '新闻同步官网成功.',
+      type: 'success'
+    })
+  }
+}
+//文件上传
+const fileRef = ref()
+function uploadHandle() {
+  fileRef.value.click()
+}
+function fileChangeHandle(evt) {
+  const target = evt.target
+  uploadFileAjax(target.files[0])
+}
+async function uploadFileAjax(file: any): Promise<void> {
+  const url = import.meta.env.VITE_UPLOAD_URL
+  const sendFData = new FormData()
+  const date = new Date()
+  const uuid: string =
+    Math.random().toString().replace('.', '') +
+    Math.random().toString().replace('.', '') +
+    date.getTime()
+  sendFData.append('path', uuid)
+  sendFData.append('file', file)
+  const result = await request.upload({ url: url, data: sendFData })
+}
+//获取详情页面
+async function queryDetailById(idStr: any): Promise<void> {
+  const urlApi = `/adm/article/query/detailById`
+  const params = {
+    id: idStr
+  }
+  const result = await request.get({ url: urlApi, params })
+  if (result) {
+    formData.value = result
+  }
+}
+const route = useRoute()
+const query = route.query
+if (query.id) {
+  eTypeRef.value = 'edit'
+  queryDetailById(query.id)
+} else {
+  restForm()
+}
+</script>
+
+<style lang="scss" scoped>
+.newsSettingBox {
+  margin-top: 20px;
+  height: calc(100% - 20px);
+  background-color: #fff;
+  border-radius: 20px;
+  padding: 20px;
+  overflow-y: auto;
+  .switchGroup {
+    display: flex;
+  }
+  .btnGroup {
+    > span {
+      margin-right: 20px;
+    }
+  }
+  .uploadFileBox {
+    position: relative;
+    flex: 1;
+    display: flex;
+    > span {
+      display: block;
+      position: absolute;
+      right: 0px;
+      top: 0px;
+    }
+  }
+  .preImg {
+    margin-bottom: 20px;
+    margin-left: 120px;
+    > img {
+      width: 200px;
+    }
+  }
+}
+</style>

+ 235 - 0
client/src/views/OaSystem/noticeAndLearn/index.vue

@@ -0,0 +1,235 @@
+<template>
+  <div class="newsSetting">
+    <div class="searchBox">
+      <el-form :inline="true" :model="formData" class="demo-form-inline">
+        <el-form-item label="标题:">
+          <el-input placeholder="请输入标题" v-model="formData.title" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" :icon="Search" @click="onSearchHandle">查询</el-button>
+          <el-button type="primary" :icon="UploadFilled" @click="onAddEditorHandle()"
+            >新增</el-button
+          >
+        </el-form-item>
+      </el-form>
+    </div>
+    <div class="tableBox">
+      <el-table :data="tableData" style="width: 100%">
+        <el-table-column type="index" label="序号" width="100" />
+        <el-table-column prop="title" label="标题">
+          <template #default="scope">
+            <a class="line-primary" href="javascript:void(0)" @click="toLookDetail(scope.row)">{{
+              scope.row['title']
+            }}</a>
+          </template>
+        </el-table-column>
+        <el-table-column prop="creatorName" label="发布人" width="120" />
+        <el-table-column label="创建时间" prop="createTime" width="200" />
+        <el-table-column label="发布时间" prop="adddate" width="200" />
+        <el-table-column label="阅读次数" prop="readNum" width="100" />
+        <el-table-column label="开关" width="120">
+          <template #default="scope">
+            <el-switch
+              active-text="是"
+              :disabled="scope.row.isPub === 0"
+              :active-value="1"
+              :inactive-value="0"
+              inline-prompt
+              inactive-text="否"
+              @change="switchHandle(scope.row)"
+              v-model="scope.row.status"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="180" align="left">
+          <template #default="scope">
+            <div class="operationBox">
+              <span @click="onAddEditorHandle(scope.row.id)">编辑</span>
+              <el-popconfirm
+                title="确定要删除该条新闻?"
+                width="180px"
+                @confirm="deleteHandle(scope.row)"
+              >
+                <template #reference>
+                  <span>删除</span>
+                </template>
+              </el-popconfirm>
+              <span v-if="scope.row.isPub === 0" @click="pushEditorHandle(scope.row)">发布</span>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <div class="pageBox">
+      <el-pagination
+        v-model:current-page="pageNo"
+        :page-size="10"
+        background
+        layout="total, prev, pager, next, jumper"
+        :total="total"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import axios from 'axios'
+import moment from 'moment'
+import { Base64 } from 'js-base64'
+import { ElMessage } from 'element-plus'
+import { useRouter } from 'vue-router'
+import request from '@/config/axios'
+import { UploadFilled, Search } from '@element-plus/icons-vue'
+
+const pageNo = ref<number>(1)
+const tableData = ref<any>([])
+const total = ref<number>()
+
+const router = useRouter()
+const formData = ref<{
+  title: string
+}>({
+  title: ''
+})
+const queryArticleByPage = async (): Promise<void> => {
+  const urlApi = `/adm/article/query/page`
+  const sendData = {
+    pageNo: pageNo.value,
+    pageSize: 10,
+    title: formData.value['title']
+  }
+  const result = await request.post({ url: urlApi, data: sendData })
+  tableData.value = result['list']
+  total.value = result['total']
+}
+const deleteHandle = async (row): Promise<void> => {
+  const id: number = row.id
+  const urlApi = `/adm/article/delete`
+  const params = {
+    id
+  }
+  const result = await request.get({ url: urlApi, params })
+  if (result) {
+    ElMessage({
+      showClose: true,
+      message: '删除成功.',
+      type: 'success'
+    })
+    queryArticleByPage()
+  }
+}
+const pushEditorHandle = (sendData) => {
+  sendData['isPub'] = 1
+  sendData['adddate'] = moment().format('YYYY-MM-DD HH:mm:ss')
+  const urlApi = `/adm/article/update`
+  request.post({ url: urlApi, data: sendData })
+  syncSiteAjax(sendData)
+}
+
+//同步官网接口——需要代理转发
+const syncSiteAjax = async (data): Promise<void> => {
+  const header = {
+    token: 'L7grJk5JnyWhsnX0D5OZ8sero5PiZkk7'
+  }
+  const body = {
+    sid: data.sid,
+    title: data.title,
+    description: data.description,
+    imgurl: data.imgurl,
+    adddate: data.adddate,
+    status: data.status,
+    content: data.content,
+    seo_title: data.seoTitle,
+    seo_keywords: data.seoKeywords,
+    seo_desc: data.seoDesc
+  }
+  const sendData = {
+    _encrypted_data: Base64.encode(JSON.stringify(body))
+  }
+  const result = await axios({
+    url: '/widewebApi/api/Article/pushNews',
+    method: 'POST',
+    data: sendData,
+    headers: header
+  })
+  if (result && result['data']) {
+    ElMessage({
+      showClose: true,
+      message: '新闻同步官网成功.',
+      type: 'success'
+    })
+  }
+}
+const switchHandle = (sendData) => {
+  const urlApi = `/adm/article/update`
+  request.post({ url: urlApi, data: sendData })
+}
+queryArticleByPage()
+const onSearchHandle = (): void => {
+  pageNo.value = 1
+  queryArticleByPage()
+}
+const onAddEditorHandle = (idStr = null): void => {
+  if (idStr) {
+    router.push({
+      path: '/noticeAndLearnEditor',
+      query: { id: idStr } as { id: number }
+    })
+  } else {
+    router.push('/noticeAndLearnEditor')
+  }
+}
+const toLookDetail = (row: any): void => {
+  router.push({
+    path: '/newlookDetail',
+    query: { id: row['id'] } as { id: number }
+  })
+}
+const handleCurrentChange = (page: number): void => {
+  pageNo.value = page
+  queryArticleByPage()
+}
+</script>
+
+<style lang="scss" scoped>
+.newsSetting {
+  margin-top: 20px;
+  height: calc(100% - 20px);
+  background-color: #fff;
+  border-radius: 20px;
+  padding: 20px;
+  position: relative;
+  > .title {
+    padding-bottom: 20px;
+    font-size: 20px;
+  }
+  > .tableBox {
+  }
+  :deep {
+    .el-table th.el-table__cell {
+      background-color: #edf2fc;
+      color: #4c525b;
+    }
+  }
+  > .pageBox {
+    padding: 20px 0px 10px 0px;
+    display: flex;
+    justify-content: right;
+  }
+  .line-primary {
+    text-decoration: none;
+    color: #4c525b;
+    &:hover {
+      color: #409eff;
+    }
+  }
+  .operationBox {
+    > span {
+      color: #409eff;
+      margin-right: 15px;
+      cursor: pointer;
+    }
+  }
+}
+</style>

+ 98 - 0
client/src/views/OaSystem/noticeAndLearn/lookDetail.vue

@@ -0,0 +1,98 @@
+<template>
+  <div class="lookDetailBox">
+    <div>
+      <h2>{{ detailForm.title }}</h2>
+      <p>
+        <span>发布时间:{{ detailForm.adddate }}</span>
+        <span style="margin: 0px 50px">阅读次数:{{ detailForm.readNum }}</span>
+        <span class="copy_line" @click="copyHandle">分享链接</span>
+      </p>
+      <div v-html="detailForm.content"></div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { useRoute } from 'vue-router'
+import request from '@/config/axios'
+import { ElMessage } from 'element-plus'
+
+const detailForm = ref<{
+  title: string
+  adddate: string
+  readNum: number
+  content: string
+}>({
+  title: '',
+  adddate: '',
+  readNum: 0,
+  content: ''
+})
+
+async function queryDetailById(idStr: any): Promise<void> {
+  const urlApi = `/adm/article/query/detailById`
+  const params = {
+    id: idStr
+  }
+  const result = await request.get({ url: urlApi, params })
+  if (result) {
+    detailForm.value = result
+  }
+}
+function addReadNum(idStr: any) {
+  const urlApi = `/adm/article/readNum/add`
+  const params = {
+    id: idStr
+  }
+  request.get({ url: urlApi, params })
+}
+function copyHandle(): void {
+  if (!query.id) return
+  const input = document.createElement('input')
+  input.style.cssText = 'opacity: 0'
+  input.type = 'text'
+  const uri = `/newsRead.html?id=${query.id}`
+  input.value = new URL(uri, import.meta.url).href
+  document.body.appendChild(input)
+  input.select()
+  document.execCommand('copy')
+  input.remove()
+  ElMessage.success('链接复制成功!')
+}
+const route = useRoute()
+const query = route.query
+if (query.id) {
+  queryDetailById(query.id)
+  addReadNum(query.id)
+}
+</script>
+<style lang="scss" scoped>
+.lookDetailBox {
+  margin-top: 20px;
+  height: calc(100% - 20px);
+  background-color: #fff;
+  border-radius: 20px;
+  padding: 40px 0px;
+  position: relative;
+  overflow-y: auto;
+  > div {
+    width: 60vw;
+    margin: auto;
+    > h2 {
+      text-align: center;
+      font-size: 36px;
+      font-weight: bold;
+    }
+    > p {
+      text-align: center;
+      padding: 40px;
+      color: #444452;
+      border-bottom: solid 1px #d8d8d8;
+      margin-bottom: 30px;
+      > .copy_line {
+        color: #409eff;
+        cursor: pointer;
+      }
+    }
+  }
+}
+</style>