liyongli преди 2 години
родител
ревизия
9fe592fa7b

+ 83 - 71
src/api/index.js

@@ -2,109 +2,121 @@ import ajax from '../utils/request.js';
 
 /**
  * 登录
- * @param {object} ori 
- * @returns 
+ * @param {object} ori
+ * @returns
  */
 export function login(ori) {
-    return ajax({
-        api: "/user/login",
-        data: ori.data,
-        method: 'POST',
-    })
+  return ajax({
+    api: '/user/login',
+    data: ori.data,
+    method: 'POST',
+  });
 }
 
 /**
  * 文案校对
- * @param {object} ori 
- * @returns 
+ * @param {object} ori
+ * @returns
  */
 export function check(ori) {
-    return ajax({
-        api: "/api/check",
-        data: ori.data,
-        method: 'POST',
-        headers: {
-            Authorization: localStorage.getItem("token")
-        }
-    })
+  return ajax({
+    api: '/api/check',
+    data: ori.data,
+    method: 'POST',
+    headers: {
+      Authorization: localStorage.getItem('token'),
+    },
+  });
 }
 
 /**
  * 热门话题
- * @param {object} ori 
- * @returns 
+ * @param {object} ori
+ * @returns
  */
-export function hotRank(ori){
-    return ajax({
-        api: "/news/hotRank/list",
-        data: ori.data,
-        method: 'POST',
-        headers: {
-            Authorization: localStorage.getItem("token")
-        }
-    })
+export function hotRank(ori) {
+  return ajax({
+    api: '/news/hotRank/list',
+    data: ori.data,
+    method: 'POST',
+    headers: {
+      Authorization: localStorage.getItem('token'),
+    },
+  });
 }
 
 /**
  * 检索新闻接口
- * @param {object} ori 
- * @returns 
+ * @param {object} ori
+ * @returns
  */
-export function searchData(ori){
-    return ajax({
-        api: "/news/data/search",
-        data: ori.data,
-        method: 'POST',
-        headers: {
-            Authorization: localStorage.getItem("token")
-        }
-    })
+export function searchData(ori) {
+  return ajax({
+    api: '/news/data/search',
+    data: ori.data,
+    method: 'POST',
+    headers: {
+      Authorization: localStorage.getItem('token'),
+    },
+  });
 }
 
 /**
  * 获得新闻分类
- * @param {object} ori 
- * @returns 
+ * @param {object} ori
+ * @returns
  */
-export function getClass(ori){
-    return ajax({
-        api: "/news/data/category",
-        data: ori.data,
-        method: 'GET',
-        headers: {
-            Authorization: localStorage.getItem("token")
-        }
-    })
+export function getClass(ori) {
+  return ajax({
+    api: '/news/data/category',
+    data: ori.data,
+    method: 'GET',
+    headers: {
+      Authorization: localStorage.getItem('token'),
+    },
+  });
 }
 
 /**
  * h5商城接口
- * @param {Object} ori 
- * @returns 
+ * @param {Object} ori
+ * @returns
  */
 export function getH5Mall(ori) {
-    return ajax({
-        api: "/oridata.json?" + Date.now(),
-        data: ori.data,
-        base: "oss1",
-        type: "ajax",
-        method: 'GET',
-        headers: {
-            Authorization: localStorage.getItem("token")
-        }
-    })
+  return ajax({
+    api: '/oridata.json?' + Date.now(),
+    data: ori.data,
+    base: 'oss1',
+    type: 'ajax',
+    method: 'GET',
+    headers: {
+      Authorization: localStorage.getItem('token'),
+    },
+  });
 }
 
 /**
  * 行政区划接口
- * @param {Object} ori 
- * @returns 
+ * @param {Object} ori
+ * @returns
  */
 export function getEconomize(ori) {
-    return ajax({
-        api: "/news/area/list",
-        data: ori.data,
-        type: "ajax",
-        method: 'GET'
-    })
-}
+  return ajax({
+    api: '/news/area/list',
+    data: ori.data,
+    type: 'ajax',
+    method: 'GET',
+  });
+}
+
+export function getreporting(ori) {
+  return ajax({
+    api: '/clue/list',
+    data: ori.data,
+    type: 'ajax',
+    method: 'POST',
+    headers: {
+      Authorization: localStorage.getItem('token'),
+    },
+  });
+}

BIN
src/assets/img/bl.png


+ 7 - 0
src/router/allMedia.js

@@ -75,6 +75,13 @@ export default [
           import(
             /* webpackChunkName: "h5mall" */ '../view/allMedia/H5Mall.vue'
           ),
+      },
+      {
+        path: 'reporting',
+        component: () =>
+          import(
+            /* webpackChunkName: "reporting" */ '../view/allMedia/reporting.vue'
+          ),
       }
     ],
   },

+ 38 - 11
src/view/allMedia/H5Editor.vue

@@ -1,6 +1,8 @@
 <template>
   <div class="H5Editor">
-    <div class="H5Editor_left">1</div>
+    <div class="H5Editor_left">
+        <component v-show="H5Editor" :is="H5EditorObj[H5Editor.type]"  :item="H5Editor"></component>
+    </div>
     <div class="H5Editor_center">
       <div class="pageClient">
         <div class="page">
@@ -58,15 +60,27 @@
 </template>
 
 <script setup>
-import { ref } from 'vue';
+import { ref, provide } from 'vue';
 import { useRoute } from 'vue-router';
 
+// 中间显示模块组件
 import H5Image from './components/H5Editor/img.vue';
 import H5Paragraph from './components/H5Editor/paragraph.vue';
 import H5FromComponent from './components/H5Editor/from.vue';
 import H5VanField from './components/H5Editor/van_field.vue';
 import H5VanButtom from './components/H5Editor/van_buttom.vue';
 
+// 左侧编辑模块组件
+import H5ImgEditor from "./components/H5Editor/imgEditor";
+
+const H5EditorObj = {
+    H5ImgEditor
+}
+const H5EditorObjEle = {
+    "image": "H5ImgEditor"
+}
+
+const H5Editor = ref({});
 const route = useRoute();
 const item = JSON.parse(route.query.item || '{}');
 const selectPage = ref(0);
@@ -76,8 +90,6 @@ const selectPageFunc = (index = 0) => {
   selectPage.value = index;
 };
 
-console.log(hoversList.value);
-
 // 查看页面大小,
 const img = new Image();
 img.src = hoversList.value[selectPage.value].background_url || '';
@@ -101,6 +113,21 @@ const backgroundStyle = () => {
 const saveParagraph = (paragraph, index) => {
   console.log(paragraph, index);
 };
+
+// provide 传递方法
+provide('starEditorFormwork', value => {
+    const type = H5EditorObjEle[value.type];
+    value.type = type;
+    H5Editor.value = value;
+});
+
+provide("saveComponents", value => {
+    console.log(value);
+})
+
+provide("deleteItemComponents", value => {
+    console.log(value);
+})
 </script>
 
 <style scoped>
@@ -114,6 +141,7 @@ const saveParagraph = (paragraph, index) => {
 .H5Editor {
   background-color: #d0cfd8;
   height: 100%;
+  min-width: 1200px;
 }
 
 .H5Editor_left,
@@ -124,7 +152,7 @@ const saveParagraph = (paragraph, index) => {
 }
 
 .H5Editor_center {
-  width: calc(100% - 500px);
+  width: calc(100% - 600px);
   position: relative;
 }
 
@@ -159,7 +187,7 @@ const saveParagraph = (paragraph, index) => {
 }
 
 .H5Editor_left {
-  width: 200px;
+  width: 300px;
   background-color: #f3f3f3;
 }
 
@@ -174,10 +202,9 @@ const saveParagraph = (paragraph, index) => {
   font-size: 16px;
 }
 
-
-.showList{
-    box-sizing: border-box;
-    border: 1px solid rgba(0,0,0,0);
-    position: relative;
+.showList {
+  box-sizing: border-box;
+  border: 1px solid rgba(0, 0, 0, 0);
+  position: relative;
 }
 </style>

+ 1 - 1
src/view/allMedia/analysis.vue

@@ -1,7 +1,7 @@
 <template>
     <el-scrollbar ref="scrollbar" class="analysis" @scroll="scroll">
       <div class="head">
-        <div class="title">分类舆情</div>
+        <div class="title">数据分析</div>
         <div class="searchRow">
           <div class="searchCol searchTitle">分类:</div>
           <div

+ 1 - 1
src/view/allMedia/analysis_map.vue

@@ -1,7 +1,7 @@
 <template>
   <el-scrollbar ref="scrollbar" class="analysis" @scroll="scroll">
     <div class="head">
-      <div class="title">分类舆情</div>
+      <div class="title">地域热点</div>
       <div class="searchRow">
         <div class="searchCol searchTitle">省:</div>
         <div

+ 26 - 39
src/view/allMedia/components/H5Editor/img.vue

@@ -1,51 +1,38 @@
 <template>
-  <div>
-    <van-popover v-model:show="showPopover"  placement="right">
-      <van-cell-group inset>
-        <van-field
-          v-model="url"
-          center
-          clearable
-          label=""
-          placeholder="请输入远程图片"
-        >
-          <template #button>
-            <van-button size="small" type="primary" @click="saveImg">更新</van-button>
-          </template>
-        </van-field>
-      </van-cell-group>
-      <template #reference>
-        <img :src="oriUrl || item.src" class="componenet_img" :style="outStyle()" />
-      </template>
-    </van-popover>
-  </div>
+  <img
+    :src="oriUrl || item.src"
+    class="componenet_img"
+    @click="editorFunc"
+    :style="outStyle()"
+  />
 </template>
 
 <script setup>
-import { defineProps, ref } from 'vue';
+import { defineProps, ref, inject } from 'vue';
+const starEditorFormwork  = inject("starEditorFormwork");
 const props = defineProps({
   item: Object,
 });
-const showPopover = ref(false);
-const url = ref("");
-const oriUrl = ref("");
-
-const saveImg = () => {
-    oriUrl.value = url.value;
-    url.value = "";
-    showPopover.value = false;
-}
+const oriUrl = ref('');
 const outStyle = () => {
-    const width = {
-        "100%": true,
-        "100vh": true
-    }
-    const styleClass = JSON.parse(JSON.stringify(props.item.style));
-    if(width[props.item.style.width]){
-        styleClass.width = '375px'
+  const width = {
+    '100%': true,
+    '100vh': true,
+  };
+  const styleClass = JSON.parse(JSON.stringify(props.item.style));
+  if (width[props.item.style.width]) {
+    styleClass.width = '375px';
+  }
+  return styleClass;
+};
+
+const editorFunc = () => {
+    const p = {
+        ...props.item
     }
-    return styleClass
-}
+    if(oriUrl.value) p.src = oriUrl.value;
+    starEditorFormwork(p);
+};
 </script>
 
 <style scoped>

+ 52 - 0
src/view/allMedia/components/H5Editor/imgEditor.vue

@@ -0,0 +1,52 @@
+<template>
+  <left-skeleton @save="save" @deleteFunc="deleteFunc">
+    <el-input v-model="inputText" placeholder="请输入在线地址或在下方上传" />
+    <el-upload
+      ref="uploadEle"
+      v-model:file-list="fileList"
+      action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
+      list-type="picture-card"
+      class="upload-demo"
+      accept="image/*"
+      :limit="1"
+    >
+      <el-icon><Plus /></el-icon>
+    </el-upload>
+  </left-skeleton>
+</template>
+
+<script setup>
+import { defineProps, ref, inject } from 'vue';
+import leftSkeleton from './leftSkeleton.vue';
+
+const inputText = ref('');
+const uploadEle = ref(null);
+const fileList = ref([]);
+const saveComponents = inject("saveComponents")
+const deleteItemComponents = inject("deleteItemComponents")
+
+const props = defineProps({
+  item: Object,
+});
+
+const save = () => {
+  uploadEle.value.submit();
+  saveComponents("保存")
+};
+
+const deleteFunc = () => {
+  /**
+   * 1.删除本地
+   * 2.删除远程
+   */
+   deleteItemComponents(props.item);
+};
+
+console.log(props.item);
+</script>
+
+<style scoped>
+.upload-demo {
+  margin-top: 1em;
+}
+</style>

+ 44 - 0
src/view/allMedia/components/H5Editor/leftSkeleton.vue

@@ -0,0 +1,44 @@
+<template>
+  <div class="imgEditor">
+    <slot></slot>
+    <div class="btngroup">
+      <el-button type="primary" round @click="save">保 存</el-button>
+      <el-button type="danger" round @click="deleteFunc">删 除</el-button>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { defineEmits } from 'vue';
+const emits = defineEmits(['save', 'deleteFunc']);
+
+const save = () => {
+    emits('save');    
+};
+
+const deleteFunc = () => {
+    emits('deleteFunc');    
+}
+</script>
+
+<style>
+.imgEditor {
+  width: 100%;
+  height: 100%;
+  padding: 1em;
+  position: relative;
+}
+.btngroup {
+  text-align: center;
+  padding: 0.5em 0;
+  position: absolute;
+  bottom: 1.5em;
+  left: 0;
+  width: 100%;
+}
+
+.btngroup .el-button {
+  width: 8em;
+}
+</style>
+

+ 10 - 3
src/view/allMedia/components/analysis_list.vue

@@ -42,14 +42,17 @@
 </template>
 
 <script setup>
-import { ref, defineExpose } from 'vue';
+import { ref, defineExpose, defineProps } from 'vue';
 import { useRouter } from 'vue-router';
-import { searchData } from '../../../api/index';
+import { searchData, getreporting } from '../../../api/index';
 let T = undefined;
 let total = -1;
 const selectValue = ref(0);
 const router = useRouter();
 const listTable = ref([]);
+const props = defineProps({
+    apiKey: String
+})
 const selectlist = [
   //   {
   //     label: '按发布时间降序',
@@ -68,6 +71,10 @@ const selectlist = [
   //     value: 3,
   //   },
 ];
+const api = {
+  getreporting,
+  searchData,
+};
 const changeSelect = () => {
   // 更改排序
   console.log(selectValue.value);
@@ -88,7 +95,7 @@ const getlist = search => {
 
   if (T) T = window.clearTimeout(T);
   T = window.setTimeout(() => {
-    searchData({
+    api[props.apiKey || 'searchData']({
       data: search,
     })
       .then(res => {

+ 113 - 0
src/view/allMedia/components/reporting_list.vue

@@ -0,0 +1,113 @@
+<template>
+  <div class="mainTitle">
+    文章列表
+  </div>
+  <br />
+  <div class="lists">
+    <!-- @click="() => toDetail(item)" -->
+    <el-table :data="listTable" style="width: 100%">
+      <el-table-column prop="title" label="标题" width="450px" />
+      <el-table-column prop="phone" label="用户名" />
+      <el-table-column prop="source" label="来源">
+        <template #default="scope"> 
+            {{source[scope.row.source - 1]}}
+        </template>
+      </el-table-column>
+      <el-table-column prop="" label="回复状态" >
+        <template #default="scope"> 
+            {{replyFlag[scope.row.replyFlag]}}
+        </template>
+      </el-table-column>
+      <el-table-column prop="createTime" label="更新时间" >
+        <template #default="scope"> 
+            {{format(scope.row.createTime)}}
+        </template>
+      </el-table-column>
+      <el-table-column prop="modifyTime" label="推送时间" >
+        <template #default="scope"> 
+            {{format(scope.row.modifyTime)}}
+        </template>
+      </el-table-column>
+      <el-table-column prop="" label="报料类型" />
+      <el-table-column prop="clueInfoCount" label="数量" />
+      <el-table-column prop="" label="操作" />
+    </el-table>
+  </div>
+</template>
+
+<script setup>
+import { ref, defineExpose } from 'vue';
+// import { useRouter } from 'vue-router';
+import dayjs from "dayjs";
+import { getreporting } from '../../../api/index';
+let T = undefined;
+let total = -1;
+// const router = useRouter();
+const listTable = ref([]);
+const source = ['热线电话','微信公众号','app', '小程序'];
+const replyFlag = ['未回复', '已回复'];
+const format = value => {
+    return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
+}
+// const toDetail = item => {
+//   router.push({
+//     path: '/analysis_detail',
+//     query: {
+//       detail: JSON.stringify(item),
+//     },
+//   });
+// };
+const getlist = search => {
+  if (search.page === 1) {
+    listTable.value = [];
+    total = -1;
+  } else if ((search.page - 1) * search.pageSize >= total) return;
+
+  if (T) T = window.clearTimeout(T);
+  T = window.setTimeout(() => {
+    getreporting({
+      data: search,
+    })
+      .then(res => {
+        const li = res.records || [];
+        listTable.value.push(...li);
+        total = res.total || 0;
+        if (T) T = window.clearTimeout(T);
+      })
+      .catch(() => {
+        if (T) T = window.clearTimeout(T);
+      });
+  }, 200);
+};
+
+defineExpose({
+  getlist,
+});
+</script>
+
+<style scoped>
+.mainTitle {
+  padding: 0 20px;
+  position: relative;
+  line-height: 60px;
+  border-bottom: 1px solid #f5f5f5;
+}
+
+.lists {
+  padding: 0.5em;
+}
+
+.list {
+  border-radius: 5px;
+  padding: 0.5em;
+  cursor: pointer;
+  line-height: 1.8em;
+  font-size: 16px;
+}
+.list:hover {
+  background-color: rgba(64, 158, 255, 0.1);
+}
+.list:not(:last-child) {
+  border-bottom: 1px dashed #b9c0d3;
+}
+</style>

+ 5 - 0
src/view/allMedia/main.vue

@@ -44,6 +44,11 @@ const menu = ref([
     icon: require('../../assets/img/sj.png'),
     path: '/main_home/analysis_map',
   },
+  {
+    title: '报料中心',
+    icon: require('../../assets/img/bl.png'),
+    path: '/main_home/reporting',
+  },
   {
     title: '数据汇聚',
     icon: require('../../assets/img/hj.png'),

+ 173 - 0
src/view/allMedia/reporting.vue

@@ -0,0 +1,173 @@
+<template>
+  <el-scrollbar ref="scrollbar" class="analysis" @scroll="scroll">
+    <div class="head">
+      <div class="title">爆料中心</div>
+      <div class="searchRow">
+        <div class="searchCol searchTitle">时间:</div>
+        <div class="searchCol">
+          <el-date-picker
+            v-model="date"
+            @change="change"
+            type="daterange"
+            :clearable="false"
+            value-format="YYYY-MM-DD"
+            range-separator="-"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+          />
+        </div>
+      </div>
+      <div class="searchRow">
+        <div class="searchCol searchTitle">搜索:</div>
+        <div class="searchCol">
+          <el-input v-model="searchText" placeholder="搜索文章">
+            <template #suffix>
+              <el-icon @click="search"><Search /></el-icon>
+            </template>
+          </el-input>
+        </div>
+      </div>
+    </div>
+    <div class="body">
+      <analysisList ref="analysisListEle" />
+    </div>
+
+    <el-icon :size="45" class="upload" v-show="showUpload" @click="upload"
+      ><Upload
+    /></el-icon>
+  </el-scrollbar>
+</template>
+
+<script setup>
+import dayjs from 'dayjs';
+import { ref, onMounted } from 'vue';
+
+import analysisList from './components/reporting_list.vue';
+
+const scrollbar = ref();
+const analysisListEle = ref();
+const showUpload = ref(false);
+const searchText = ref('');
+const date = ref([]);
+
+const pageSize = 10;
+let page = 1;
+let totalPage = 0;
+
+onMounted(() => {
+  getList();
+});
+
+const getList = () => {
+  if (page <= totalPage) return;
+  const search = {
+    keywords: searchText.value,
+    page: page++,
+    size: pageSize,
+  };
+  // 时间区间
+  if (date.value[0]) search.start = dayjs(date.value[0]).format('YYYY-MM-DD HH:mm:ss');
+  if (date.value[1]) search.end = dayjs(date.value[1]).format('YYYY-MM-DD HH:mm:ss');
+  analysisListEle.value.getlist(search);
+};
+
+const change = () => {
+  date.value = [date.value[0] + ' 00:00:00', date.value[1] + ' 23:59:59'];
+  page = 1;
+  getList();
+};
+
+const search = () => {
+  page = 1;
+  getList();
+};
+
+const scroll = e => {
+  const height =
+    document.querySelector('.analysis .head').offsetHeight +
+    document.querySelector('.analysis .body').offsetHeight -
+    document.querySelector('.analysis').offsetHeight;
+  const scrollNum = e.scrollTop.toFixed(2) - 0;
+  if (!showUpload.value && scrollNum > 180) showUpload.value = true;
+  else if (scrollNum <= 180) showUpload.value = false;
+  if (height - scrollNum > 0) return;
+  getList();
+};
+
+const upload = () => {
+  scrollbar.value.setScrollTop(0);
+};
+</script>
+
+<style scoped>
+.analysis {
+  height: 100%;
+  min-width: 1305px;
+  position: relative;
+}
+.analysis .head,
+.analysis .body {
+  margin: 0 1em;
+  min-width: 855px;
+}
+
+.analysis .body {
+  border: 1px solid #f3f3f3;
+  margin: 1em;
+}
+
+.title {
+  font-size: 18px;
+  font-weight: 600;
+  height: 49px;
+  line-height: 49px;
+  padding-left: 8px;
+  border-bottom: 1px solid #f5f5f5;
+}
+
+.searchRow {
+  margin: 0.5em 0;
+}
+
+.searchCol {
+  display: inline-block;
+  margin: 0 0.5em;
+  padding: 0 0.5em;
+  height: 35px;
+  line-height: 35px;
+  cursor: pointer;
+}
+.searchCol:hover {
+  color: rgb(64, 158, 255);
+}
+
+.searchActive {
+  font-weight: 600;
+  color: rgb(64, 158, 255);
+  border-radius: 5px;
+  background-color: rgba(64, 158, 255, 0.1);
+  border-bottom: none;
+}
+
+.searchRow .searchTitle {
+  color: #b9c0d3;
+}
+
+.body .el-checkbox {
+  margin-right: 15px;
+}
+
+.source {
+  color: #22ac38;
+}
+
+.upload {
+  position: absolute;
+  right: 25px;
+  bottom: 25px;
+  background-color: #e9e9e990;
+  border-radius: 50%;
+  padding: 5px;
+  cursor: pointer;
+}
+</style>