Эх сурвалжийг харах

✨ feat<reportManage>: 数据录入、任务管理

任务管理新建任务接口
xinyan 1 жил өмнө
parent
commit
f8e1c8117f

+ 45 - 3
src/views/reportManage/dataCenter/api.ts

@@ -1,9 +1,6 @@
 import { request } from '/@/utils/service'
 import {UserPageQuery} from "@fast-crud/fast-crud";
 
-
-
-
 export const apiPrefix = '/api/sellers/product/trend/daily/'
 
 export function getCardData(query: UserPageQuery) {
@@ -38,3 +35,48 @@ export function getLineMonthData(query: UserPageQuery) {
         params: query,
     })
 }
+export function postCreateTask(body) {
+    return request({
+        url: '/api/report_manage/summary-tasks/',
+        method: 'POST',
+        data: body,
+    })
+}
+
+export function getTasks(query) {
+    return request({
+        url: '/api/report_manage/summary-tasks/',
+        method: 'GET',
+        params: query,
+    })
+}
+
+export  function postDeleteProductLine(body) {
+    return request({
+        url: '/api/report_manage/summary-tasks/8/delete/',
+        method: 'POST',
+        data: body,
+    })
+}
+
+export function getOperationSelect(query) {
+    return request({
+        url: '/api/system/user-select/',
+        method: 'GET',
+        params: query,
+    })
+}
+// export function getQuantitySelect(query) {
+//     return request({
+//         url: '',
+//         method: 'get',
+//         params: query,
+//     })
+// }
+export function postUpdateTask(body) {
+    return request({
+        url: `/api/report_manage/summary-tasks/${body.id}/`,
+        method: 'POST',
+        data: body,
+    });
+}

+ 211 - 131
src/views/reportManage/dataCenter/components/DataExport.vue

@@ -1,163 +1,243 @@
 <template>
   <div>
-    <vxe-grid ref="xGrid" v-bind="gridOptions" v-on="gridEvents">
-      <template #operate="{ row }">
-        <template v-if="hasActiveEditRow(row)">
-          <vxe-button content="取消" @click="clearRowEvent"></vxe-button>
-          <vxe-button status="primary" content="保存" @click="saveRowEvent(row)"></vxe-button>
-        </template>
-        <template v-else>
-          <vxe-button content="编辑" @click="editRowEvent(row)"></vxe-button>
-        </template>
-        <vxe-button status="danger" content="删除" @click="removeRowEvent(row)"></vxe-button>
+    <vxe-toolbar>
+      <template #buttons>
+        <vxe-button icon="vxe-icon-square-plus" @click="insertEvent()">新增</vxe-button>
       </template>
+    </vxe-toolbar>
+    <vxe-table
+        border
+        show-overflow
+        ref="tableRef"
+        height="300"
+        :column-config="{resizable: true}"
+        :row-config="{isHover: true}"
+        :data="tableData"
+        @cell-dblclick="cellDBLClickEvent">
+      <vxe-column type="seq" width="60"></vxe-column>
+      <vxe-column field="name" title="Name"></vxe-column>
+      <vxe-column field="sex" title="Sex" :formatter="formatterSex"></vxe-column>
+      <vxe-column field="age" title="Age"></vxe-column>
+      <vxe-column field="address" title="Address" show-overflow></vxe-column>
+      <vxe-column title="操作" width="100" show-overflow>
+        <template #default="{ row }">
+          <vxe-button mode="text" icon="vxe-icon-edit" @click="editEvent(row)"></vxe-button>
+          <vxe-button mode="text" icon="vxe-icon-delete" @click="removeEvent(row)"></vxe-button>
+        </template>
+      </vxe-column>
+    </vxe-table>
 
-      <template #Name_edit="{ row }">
-        <vxe-input v-model="row.Name"></vxe-input>
-      </template>
-      <template #DailyDataHeader_edit="{ row }">
-        <vxe-input v-model="row.DailyDataHeader"></vxe-input>
-      </template>
-      <template #WeeklyDataHeader_edit="{ row }">
-        <vxe-input v-model="row.WeeklyDataHeader"></vxe-input>
-      </template>
-      <template #MonthlyDataHeader_edit="{ row }">
-        <vxe-input v-model="row.MonthlyDataHeader"></vxe-input>
-      </template>
-      <template #CreationTime_edit="{ row }">
-        <vxe-input v-model="row.CreationTime"></vxe-input>
+    <vxe-modal v-model="showEdit" :title="selectRow ? '编辑&保存' : '新增&保存'" width="800" min-width="600" min-height="300" :loading="submitLoading" resize destroy-on-close>
+      <template #default>
+        <vxe-form :data="formData" :rules="formRules" title-align="right" title-width="100" @submit="submitEvent">
+          <vxe-form-item title="Basic information" title-align="left" :title-width="200" :span="24" :title-prefix="{icon: 'vxe-icon-comment'}"></vxe-form-item>
+          <vxe-form-item field="name" title="Name" :span="12" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-input v-model="data.name" placeholder="请输入名称"></vxe-input>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item field="nickname" title="Nickname" :span="12" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-input v-model="data.name" placeholder="请输入名称"></vxe-input>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item field="role" title="Role" :span="12" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-input v-model="data.name" placeholder="请输入角色"></vxe-input>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item field="sex" title="Sex" :span="12" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-select v-model="data.sex" transfer>
+                <vxe-option v-for="item in sexList" :key="item.value" :value="item.value" :label="item.label"></vxe-option>
+              </vxe-select>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item field="age" title="Age" :span="12" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-input v-model="data.age" type="number" placeholder="请输入年龄"></vxe-input>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item field="flag1" title="是否单身" :span="12" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-radio-group v-model="data.flag1">
+                <vxe-radio label="Y" content="是"></vxe-radio>
+                <vxe-radio label="N" content="否"></vxe-radio>
+              </vxe-radio-group>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item field="checkedList" title="可选信息" :visible-method="visibleMethod" :span="24" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-checkbox-group v-model="data.checkedList">
+                <vxe-checkbox label="1" content="运动、跑步"></vxe-checkbox>
+                <vxe-checkbox label="2" content="听音乐"></vxe-checkbox>
+                <vxe-checkbox label="3" content="爬山"></vxe-checkbox>
+                <vxe-checkbox label="4" content="吃美食"></vxe-checkbox>
+              </vxe-checkbox-group>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item title="Other information" title-align="left" :title-width="200" :span="24" :title-prefix="{message: '请填写必填项', icon: 'vxe-icon-info-circle-fill'}"></vxe-form-item>
+          <vxe-form-item field="num" title="Number" :span="12" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-input v-model="data.num" type="number" placeholder="请输入数值"></vxe-input>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item field="date3" title="Date" :span="12" :item-render="{}">
+            <template #default="{ data }">
+              <vxe-input v-model="data.date3" type="date" placeholder="请选择日期" transfer></vxe-input>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item field="address" title="Date" :span="24" :item-render="{}" :title-suffix="{message: '提示信息!!', icon: 'vxe-icon-question-circle-fill'}">
+            <template #default="{ data }">
+              <vxe-textarea v-model="data.address" :autosize="{minRows: 2, maxRows: 4}"></vxe-textarea>
+            </template>
+          </vxe-form-item>
+          <vxe-form-item align="center" title-align="left" :span="24">
+            <template #default>
+              <vxe-button type="submit">提交</vxe-button>
+              <vxe-button type="reset">重置</vxe-button>
+            </template>
+          </vxe-form-item>
+        </vxe-form>
       </template>
-    </vxe-grid>
+    </vxe-modal>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive } from 'vue'
-import { VXETable, VxeGridInstance, VxeGridProps, VxeGridListeners } from 'vxe-table'
+import { reactive, ref } from 'vue'
+import { VXETable, VxeTableInstance, VxeColumnPropTypes, VxeFormPropTypes, VxeFormItemPropTypes, VxeTableEvents } from 'vxe-table'
 
 interface RowVO {
-  Name: string
-  DailyDataHeader: string
-  WeeklyDataHeader: string
-  MonthlyDataHeader: string
-  CreationTime: number
+  id: number
+  name: string
+  nickname: string
+  role: string
+  sex: string
+  sex2: string[]
+  num: number
+  num1: number
+  age: number
+  flag1: boolean
+  address: string
+  date12: string
+  date13: string
+  date3: string
+  checkedList: any[]
 }
 
-const xGrid = ref<VxeGridInstance<RowVO>>()
-
-const gridOptions = reactive<VxeGridProps<RowVO>>({
-  border: true,
-  keepSource: true,
-  showOverflow: true,
-  height: 530,
-  loading: false,
-  columnConfig: {
-    resizable: true
-  },
-  pagerConfig: {
-    enabled: true,
-    total: 0,
-    currentPage: 1,
-    pageSize: 10,
-    pageSizes: [10, 20, 50, 100, 200, 500]
-  },
-  editConfig: {
-    trigger: 'manual',
-    mode: 'row',
-    showStatus: true
-  },
-  columns: [
-    { field: 'Name', title: '模板名称', editRender: { autofocus: '.vxe-input--inner' }, slots: { edit: 'Name_edit' } },
-    { field: 'DailyDataHeader', title: '日数据表头', editRender: { autofocus: '.vxe-input--inner' }, slots: { edit: 'DailyDataHeader_edit' } },
-    { field: 'WeeklyDataHeader', title: '周数据表头', editRender: {}, slots: { edit: 'WeeklyDataHeader_edit' } },
-    { field: 'MonthlyDataHeader', title: '月数据表头', editRender: {}, slots: { edit: 'MonthlyDataHeader_edit' } },
-    { field: 'CreationTime', title: '创建时间', editRender: {}, slots: { edit: 'CreationTime_edit' } },
-    { title: '操作', width: 300, slots: { default: 'operate' } }
-  ],
-  data: []
+const tableRef = ref<VxeTableInstance<RowVO>>()
+
+const formData = reactive({
+  name: '',
+  nickname: '',
+  role: '',
+  sex: '',
+  age: 0,
+  num: 0,
+  checkedList: [] as any[],
+  flag1: false,
+  date3: '',
+  address: ''
 })
 
+const submitLoading = ref(false)
+const showEdit = ref(false)
+const selectRow = ref<RowVO | null>()
+const tableData = ref<RowVO[]>([])
 
-const findList = () => {
-  gridOptions.loading = true
-  setTimeout(() => {
-    gridOptions.loading = false
-    if (gridOptions.pagerConfig) {
-      gridOptions.pagerConfig.total = 10
-    }
-    gridOptions.data = [
-      {
-        Name: 'John Brown',
-        DailyDataHeader: 'New York No. 1 Lake Park',
-        WeeklyDataHeader: 'New York No. 1 Lake Park',
-        MonthlyDataHeader: 'New York No. 1 Lake Park',
-        'CreationTime': '2016-10-03',
-      },
-        {
-          Name: 'Jim Green',
-          DailyDataHeader: 'London No. 1 Lake Park',
-          WeeklyDataHeader: 'London No. 1 Lake Park',
-          MonthlyDataHeader: 'London No. 1 Lake Park',
-          'CreationTime': '2016-10-01',
-        },
-    ]
-  }, 300)
-}
+const sexList = ref([
+  { label: '女', value: '0' },
+  { label: '男', value: '1' }
+])
 
-const gridEvents: VxeGridListeners<RowVO> = {
-  pageChange ({ currentPage, pageSize }) {
-    if (gridOptions.pagerConfig) {
-      gridOptions.pagerConfig.currentPage = currentPage
-      gridOptions.pagerConfig.pageSize = pageSize
-    }
-    findList()
-  }
+const formRules = reactive<VxeFormPropTypes.Rules>({
+  name: [
+    { required: true, message: '请输入名称' },
+    { min: 3, max: 5, message: '长度在 3 到 5 个字符' }
+  ],
+  nickname: [
+    { required: true, message: '请输入昵称' }
+  ],
+  sex: [
+    { required: true, message: '请选择性别' }
+  ]
+})
+
+const formatterSex: VxeColumnPropTypes.Formatter<RowVO> = ({ cellValue }) => {
+  const item = sexList.value.find(item => item.value === cellValue)
+  return item ? item.label : ''
 }
 
-const hasActiveEditRow = (row: RowVO) => {
-  const $grid = xGrid.value
-  if ($grid) {
-    return $grid.isEditByRow(row)
-  }
-  return false
+const visibleMethod: VxeFormItemPropTypes.VisibleMethod = ({ data }) => {
+  return data.flag1 === 'Y'
 }
 
-const editRowEvent = (row: RowVO) => {
-  const $grid = xGrid.value
-  if ($grid) {
-    $grid.setEditRow(row)
-  }
+const insertEvent = () => {
+  Object.assign(formData, {
+    name: '',
+    nickname: '',
+    role: '',
+    sex: '',
+    age: 0,
+    num: 0,
+    checkedList: [],
+    flag1: false,
+    date3: '',
+    address: ''
+  })
+  selectRow.value = null
+  showEdit.value = true
 }
 
-const clearRowEvent = () => {
-  const $grid = xGrid.value
-  if ($grid) {
-    $grid.clearEdit()
-  }
+const editEvent = (row: RowVO) => {
+  Object.assign(formData, row)
+  selectRow.value = row
+  showEdit.value = true
 }
 
-const saveRowEvent = async (row: RowVO) => {
-  const $grid = xGrid.value
-  if ($grid) {
-    await $grid.clearEdit()
-    gridOptions.loading = true
-    // 模拟异步保存
-    setTimeout(() => {
-      gridOptions.loading = false
-      VXETable.modal.message({ content: `${JSON.stringify(row)}`, status: 'success' })
-    }, 300)
-  }
+const cellDBLClickEvent: VxeTableEvents.CellDblclick<RowVO> = ({ row }) => {
+  editEvent(row)
 }
 
-const removeRowEvent = async (row: RowVO) => {
+const removeEvent = async (row: RowVO) => {
   const type = await VXETable.modal.confirm('您确定要删除该数据?')
-  const $grid = xGrid.value
-  if ($grid) {
-    if (type === 'confirm') {
-      await $grid.remove(row)
+  if (type === 'confirm') {
+    const $table = tableRef.value
+    if ($table) {
+      $table.remove(row)
     }
   }
 }
 
-findList()
-</script>
+const submitEvent = () => {
+  submitLoading.value = true
+  setTimeout(() => {
+    const $table = tableRef.value
+    if ($table) {
+      submitLoading.value = false
+      showEdit.value = false
+      if (selectRow.value) {
+        VXETable.modal.message({ content: '保存成功', status: 'success' })
+        Object.assign(selectRow.value, formData)
+      } else {
+        VXETable.modal.message({ content: '新增成功', status: 'success' })
+        $table.insert({ ...formData })
+      }
+    }
+  }, 500)
+}
+
+setTimeout(() => {
+  const list: RowVO[] = [
+    { id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: '0', sex2: ['0'], num: 40, num1: 40, age: 28, flag1: false, address: 'Shenzhen', date3: '', date12: '', date13: '', checkedList: [] },
+    { id: 10002, name: 'Test2', nickname: 'T2', role: 'Designer', sex: '1', sex2: ['0', '1'], num: 40, num1: 20, age: 22, flag1: false, address: 'Guangzhou', date3: '', date12: '', date13: '2020-08-20', checkedList: [] },
+    { id: 10003, name: 'Test3', nickname: 'T3', role: 'Test', sex: '0', sex2: ['1'], num: 4, num1: 200, age: 32, flag1: true, address: 'Shanghai', date3: '', date12: '2020-09-10', date13: '', checkedList: [] },
+    { id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: '1', sex2: ['0'], num: 3, num1: 30, age: 23, flag1: false, address: 'Shenzhen', date3: '', date12: '', date13: '2020-12-04', checkedList: [] },
+    { id: 10004, name: 'Test5', nickname: 'T5', role: 'Designer', sex: '1', sex2: ['1'], num: 40, num1: 30, age: 26, flag1: true, address: 'Shenzhen', date3: '', date12: '', date13: '', checkedList: [] },
+    { id: 10004, name: 'Test6', nickname: 'T6', role: 'Designer', sex: '1', sex2: ['1'], num: 5, num1: 30, age: 28, flag1: false, address: 'BeiJing', date3: '', date12: '', date13: '2020-09-04', checkedList: [] },
+    { id: 10004, name: 'Test7', nickname: 'T7', role: 'Designer', sex: '1', sex2: ['1'], num: 40, num1: 30, age: 30, flag1: false, address: 'BeiJing', date3: '', date12: '', date13: '2020-04-10', checkedList: [] }
+  ]
+  tableData.value = list
+}, 100)
+</script>

+ 166 - 29
src/views/reportManage/dataCenter/components/EntryDetail.vue

@@ -1,10 +1,12 @@
 <script setup lang="ts">
-import { reactive } from 'vue'
-import { VxeGridProps } from 'vxe-table'
-import DateRangePicker from "/@/components/DateRangePicker/index.vue";
+import { reactive,ref} from 'vue'
+import { VXETable, VxeGridInstance, VxeGridProps, VxeGridListeners} from 'vxe-table'
 import dayjs from 'dayjs';
+import { useRouter } from 'vue-router'
+const router = useRouter()
 
-const DailyEntryTime = ref(dayjs().format('YYYY-MM-DD')); // 使用dayjs获取当前日期并格式化为'YYYY-MM-DD'
+const DailyEntryTime = ref(dayjs().format('YYYY-MM-DD'));
+const DailyTime = ref(dayjs().format('YYYY-MM-DD'));
 
 const shortcuts = [
   {
@@ -30,32 +32,140 @@ const shortcuts = [
 ];
 
 //表格
+interface RowVO {
+  id: number
+  name: string
+  country: string
+  brand: string
+  sales: string
+  totalAdSales: number
+  adSpend: string
+}
+
+const xGrid = ref<VxeGridInstance<RowVO>>()
 const tableColumns = [
   { type: 'seq', title: 'ID', width: 50 },
-  { field: 'Name', title: '平台名称' },
-  { field: 'Country', title: '国家' },
-  { field: 'Brand', title: '品牌' },
-  { field: 'Sales', title: '销售额' },
-  { field: 'TotalAdSales', title: '广告销售额' },
-  { field: 'AdSpend', title: '广告花费' },
+  { field: 'name', title: '平台名称', },
+  { field: 'country', title: '国家',},
+  { field: 'brand', title: '品牌',  },
+
+  { field: 'sales', title: '销售额', editRender: { autofocus: '.vxe-input--inner' }, slots: { edit: 'sales_edit' }},
+  { field: 'totalAdSales', title: '广告销售额', editRender: { autofocus: '.vxe-input--inner' }, slots: { edit: 'totalAdSales_edit' }},
+  { field: 'adSpend', title: '广告花费', editRender: { autofocus: '.vxe-input--inner' }, slots: { edit: 'adSpend_edit' }},
+  { title: '操作', width: 300, slots: { default: 'operate' } }
 ]
 
 const gridOptions = reactive<VxeGridProps<RowVO>>({
   border: true,
-  height: 300,
-  align: null,
+  keepSource: true,
+  showOverflow: true,
+  height: 530,
+  loading: false,
   columnConfig: {
-    resizable: true,
+    resizable: true
+  },
+  pagerConfig: {
+    enabled: true,
+    total: 0,
+    currentPage: 1,
+    pageSize: 10,
+    pageSizes: [10, 20, 50, 100, 200, 500]
+  },
+  editConfig: {
+    trigger: 'manual',
+    mode: 'row',
+    showStatus: true,
   },
-
   columns: tableColumns,
   toolbarConfig: {
     slots: {
       buttons: 'toolbar_buttons',
     },
   },
-  data: [{ Name: 10001, Country: 'Test1', Brand: 'T1', Sales: 'Develop', TotalAdSales: 11, AdSpend: 28 }],
+  data: []
 })
+const findList = () => {
+  gridOptions.loading = true
+  setTimeout(() => {
+    gridOptions.loading = false
+    if (gridOptions.pagerConfig) {
+      gridOptions.pagerConfig.total = 10
+    }
+    gridOptions.data = [
+      { name: 'Test1', country: 'T1', brand: 'B1', sales: 'Develop', totalAdSales: '1', adSpend: 28},
+      { name: 'Test2', country: 'T2', brand: 'B2', sales: 'Test', totalAdSales: '2', adSpend: 28},
+      { name: 'Test3', country: 'T3', brand: 'B3', sales: 'Test', totalAdSales: '3', adSpend: 28},
+      { name: 'Test4', country: 'T4', brand: 'B4', sales: 'Test', totalAdSales: '4', adSpend: 28},
+    ]
+  }, 300)
+}
+
+const gridEvents: VxeGridListeners<RowVO> = {
+  pageChange ({ currentPage, pageSize }) {
+    if (gridOptions.pagerConfig) {
+      gridOptions.pagerConfig.currentPage = currentPage
+      gridOptions.pagerConfig.pageSize = pageSize
+    }
+    findList()
+  }
+}
+
+const hasActiveEditRow = (row: RowVO) => {
+  const $grid = xGrid.value
+  if ($grid) {
+    return $grid.isEditByRow(row)
+  }
+  return false
+}
+
+const editRowEvent = (row: RowVO) => {
+  const $grid = xGrid.value
+  if ($grid) {
+    $grid.setEditRow(row)
+  }
+}
+
+const clearRowEvent = () => {
+  const $grid = xGrid.value
+  if ($grid) {
+    $grid.clearEdit()
+  }
+}
+
+const saveRowEvent = async (row: RowVO) => {
+  const $grid = xGrid.value
+  if ($grid) {
+    await $grid.clearEdit()
+    gridOptions.loading = true
+    // 模拟异步保存
+    setTimeout(() => {
+      gridOptions.loading = false
+      VXETable.modal.message({ content: `${JSON.stringify(row)}`, status: 'success' })
+    }, 300)
+  }
+}
+
+const removeRowEvent = async (row: RowVO) => {
+  const type = await VXETable.modal.confirm('您确定要删除该数据?')
+  const $grid = xGrid.value
+  if ($grid) {
+    if (type === 'confirm') {
+      await $grid.remove(row)
+    }
+  }
+}
+
+// const editDisabledEvent: VxeGridEvents.EditDisabled = () => {
+//   console.log('禁止编辑')
+// }
+// @edit-disabled="editDisabledEvent"
+
+findList()
+const returnHome = (row: any) => {
+  router.push({
+    name:'DataCenter'
+  })
+}
 </script>
 
 <template>
@@ -70,26 +180,50 @@ const gridOptions = reactive<VxeGridProps<RowVO>>({
         />
       </div>
       <div class="block">
-        <span class="demonstration">销售额数据时间:</span>
+        <span class="demonstration">数据时间:</span>
         <el-date-picker
-            v-model="SalesDataTime"
-            type="Date"
-            :size="size"
-        />
-      </div>
-      <div class="block">
-        <span class="demonstration">广告数据时间:</span>
-        <el-date-picker
-            v-model="AdDataTime"
+            v-model="DailyTime"
             type="Date"
             :size="size"
         />
       </div>
     </div>
-    <vxe-grid v-bind="gridOptions">
-      <template #toolbar_buttons></template>
-    </vxe-grid>
   </div>
+    <el-card>
+        <div>
+          <vxe-grid ref="xGrid" v-bind="gridOptions" v-on="gridEvents" >
+            <template #operate="{ row }">
+              <template v-if="hasActiveEditRow(row)">
+                <vxe-button content="取消" @click="clearRowEvent"></vxe-button>
+                <vxe-button status="primary" content="保存" @click="saveRowEvent(row)"></vxe-button>
+              </template>
+              <template v-else>
+                <vxe-button content="编辑" @click="editRowEvent(row)"></vxe-button>
+              </template>
+              <vxe-button status="danger" content="删除" @click="removeRowEvent(row)"></vxe-button>
+            </template>
+            <!--<template #name_edit="{ row }">-->
+            <!--  <vxe-input v-model="row.name"></vxe-input>-->
+            <!--</template>-->
+            <!--<template #country_edit="{ row }">-->
+            <!--  <vxe-input v-model="row.country"></vxe-input>-->
+            <!--</template>-->
+            <!--<template #brand_edit="{ row }">-->
+            <!--  <vxe-input v-model="row.brand"></vxe-input>-->
+            <!--</template>-->
+            <template #sales_edit="{ row }">
+              <vxe-input v-model="row.sales"></vxe-input>
+            </template>
+            <template #totalAdSales_edit="{ row }">
+              <vxe-input v-model="row.totalAdSales"></vxe-input>
+            </template>
+            <template #adSpend_edit="{ row }">
+              <vxe-input v-model="row.adSpend"></vxe-input>
+            </template>
+          </vxe-grid>
+        </div>
+      <!--<vxe-button @click="returnHome">确认</vxe-button>-->
+    </el-card>
 </template>
 
 <style scoped>
@@ -105,7 +239,10 @@ const gridOptions = reactive<VxeGridProps<RowVO>>({
 .demo-date-picker .demonstration {
   color: var(--el-text-color-secondary);
   font-size: 14px;
-  /*margin-bottom: 20px;*/
   margin:10px;
 }
+.vxe-grid {
+  border-radius: 10px;
+  margin-bottom: 10px;
+}
 </style>

+ 12 - 42
src/views/reportManage/dataCenter/components/NormalDisplay.vue

@@ -8,10 +8,8 @@ import { storeToRefs } from 'pinia'
 import { useShopInfo } from '/@/stores/shopInfo'
 import { usePublicData } from '/@/stores/publicData'
 import { useRouter } from 'vue-router'
-
+import Selector from "/@/views/reportManage/dataCenter/components/Selector/index.vue";
 const router = useRouter()
-// import router from "/@/router";
-import DataEntry from "/src/views/reportManage/dataCenter/components/EntryDetail.vue";
 // 店铺信息
 const shopInfo = useShopInfo()
 const { profile } = storeToRefs(shopInfo)
@@ -26,21 +24,7 @@ const queryParams = ref({
   // childAsin,
   // sku,
 })
-// 筛选条件
-const value1 = ref([]) // 平台编号
-const value2 = ref([])
-const value3 = ref([])
-const value4 = ref([])
-const options = [
-  {
-    value: 'Option1',
-    label: 'Option1',
-  },
-  {
-    value: 'Option2',
-    label: 'Option2',
-  },
-]
+
 const tableColumns = [
   { type: 'seq', title: '平台编号' },
   { field: 'Name', title: '平台名称' },
@@ -61,7 +45,7 @@ const tableColumns = [
 //表格
 const gridOptions = reactive({
   border: true,
-  height: 300,
+  height: 600,
   align: null,
   round: true,
   columnConfig: {
@@ -99,30 +83,17 @@ const handleImport = (row: any) => {
     name: 'EntryDetail',
   })
 }
-
-
+const QueryTask = (row: any) => {
+  router.push({
+    name: 'TaskManage',
+  })
+}
 </script>
 
 <template>
   <div>
     <div class="flex gap-1.5 justify-between">
-      <div class="flex gap-1.5">
-        <el-select v-model="value1" multiple placeholder="平台编号" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-        <el-select v-model="value2" multiple placeholder="平台名称" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-        <el-select v-model="value3" multiple placeholder="运营" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-        <el-select v-model="value4" multiple placeholder="国家" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-        <el-select v-model="value4" multiple placeholder="品牌" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-      </div>
+      <Selector></Selector>
       <DateRangePicker v-model="dateRange"></DateRangePicker>
     </div>
     <el-card class="mb-1.5">
@@ -136,13 +107,12 @@ const handleImport = (row: any) => {
         >np
       </DataTendencyChart>
     </el-card>
-    </div>
+  </div>
     <el-card>
       <vxe-grid v-bind="gridOptions">
         <template #toolbar_buttons>
-          <!--TODO: 数据录入-->
           <vxe-button @click="handleImport">数据录入</vxe-button>
-          <vxe-button @click="">任务列表</vxe-button>
+          <vxe-button @click="QueryTask">任务列表</vxe-button>
         </template>
       </vxe-grid>
     </el-card>
@@ -150,6 +120,6 @@ const handleImport = (row: any) => {
 
 <style scoped>
 .vxe-grid {
-  border-radius: 8px; /* 更改这个值以设置你想要的圆角大小 */
+  border-radius: 10px;
 }
 </style>

+ 42 - 0
src/views/reportManage/dataCenter/components/Selector/index.vue

@@ -0,0 +1,42 @@
+<script setup lang="ts">
+import {ref} from "vue";
+
+const value1 = ref([]) // 平台编号
+const value2 = ref([])
+const value3 = ref([])
+const value4 = ref([])
+const options = [
+  {
+    value: 'Option1',
+    label: 'Option1',
+  },
+  {
+    value: 'Option2',
+    label: 'Option2',
+  },
+]
+</script>
+
+<template>
+    <div class="flex gap-1.5">
+      <el-select v-model="value1" multiple placeholder="平台编号" style="width: 160px">
+        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+      </el-select>
+      <el-select v-model="value2" multiple placeholder="平台名称" style="width: 160px">
+        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+      </el-select>
+      <el-select v-model="value3" multiple placeholder="运营" style="width: 160px">
+        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+      </el-select>
+      <el-select v-model="value4" multiple placeholder="国家" style="width: 160px">
+        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+      </el-select>
+      <el-select v-model="value4" multiple placeholder="品牌" style="width: 160px">
+        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+      </el-select>
+    </div>
+</template>
+
+<style scoped>
+
+</style>

+ 2 - 32
src/views/reportManage/dataCenter/components/TableBrowsing.vue

@@ -7,6 +7,7 @@ import DateRangePicker from '/@/components/DateRangePicker/index.vue'
 import { storeToRefs } from 'pinia'
 import { useShopInfo } from '/@/stores/shopInfo'
 import { usePublicData } from '/@/stores/publicData'
+import Selector from '/@/views/reportManage/dataCenter/components/Selector/index.vue'
 
 // 店铺信息
 const shopInfo = useShopInfo()
@@ -22,21 +23,6 @@ const queryParams = ref({
   // childAsin,
   // sku,
 })
-// 筛选条件
-const value1 = ref([]) // 平台编号
-const value2 = ref([])
-const value3 = ref([])
-const value4 = ref([])
-const options = [
-  {
-    value: 'Option1',
-    label: 'Option1',
-  },
-  {
-    value: 'Option2',
-    label: 'Option2',
-  },
-]
 const tableColumns = [
   { type: 'seq', title: '平台编号' },
   { field: 'Name', title: '平台名称' },
@@ -106,23 +92,7 @@ const gridOptions = reactive({
 <template>
   <div>
     <div class="flex gap-1.5 justify-between">
-      <div class="flex gap-1.5">
-        <el-select v-model="value1" multiple placeholder="平台编号" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-        <el-select v-model="value2" multiple placeholder="平台名称" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-        <el-select v-model="value3" multiple placeholder="运营" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-        <el-select v-model="value4" multiple placeholder="国家" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-        <el-select v-model="value4" multiple placeholder="品牌" style="width: 160px">
-          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-      </div>
+      <Selector></Selector>
       <DateRangePicker v-model="dateRange"></DateRangePicker>
     </div>
 

+ 428 - 2
src/views/reportManage/dataCenter/components/TaskManage.vue

@@ -1,11 +1,437 @@
 <script setup lang="ts">
+import Selector from '/@/views/reportManage/dataCenter/components/Selector/index.vue'
+import {ref, reactive, onMounted, nextTick } from 'vue'
+import {VXETable, VxeGridInstance, VxeGridProps, VxeGridListeners} from 'vxe-table'
+import {getTasks, postCreateTask, getOperationSelect ,postUpdateTask } from '../api'
+import {ComponentSize, ElMessage, FormInstance, FormRules} from 'element-plus'
 
+//表单
+interface taskRuleForm {
+  number: string
+  name: string
+  country: string
+  brand: string
+  operation: string[]
+  currency: string
+}
+
+const formSize = ref<ComponentSize>('default')
+const dialogFormVisible = ref(false)
+const taskRuleFormRef = ref<FormInstance>()
+const taskRuleForm = reactive({
+  number: '',
+  name: '',
+  country: '',
+  brand: '',
+  operation: '',
+  currency: '',
+})
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.resetFields()
+}
+const rules = reactive<FormRules>({
+  number: [{required: true, message: '请输入平台编号', trigger: 'blur'},],
+  name: [{required: true, message: '请输入平台名称', trigger: 'blur'}],
+  country: [{required: true, message: '请输入国家', trigger: 'blur'}],
+  brand: [{required: true, message: '请输入品牌', trigger: 'blur'}],
+  operation: [{required: true, message: '请选择运营', trigger: 'change'}],
+  currency: [{required: true, message: '请输入货币', trigger: 'blur'}],
+})
+
+//表格
+let page = 1
+let limit = 10
+const  loading = ref(false)
+
+interface RowVO {
+  platformNumber: string
+  platformName: string
+  country: string
+  brandName: string
+  operation: string
+  currencyCode: string
+  quantity: number
+}
+
+const xGrid = ref<VxeGridInstance<RowVO>>()
+
+const gridOptions = reactive<VxeGridProps<RowVO>>({
+  border: false,
+  keepSource: true,
+  showOverflow: true,
+  height: 500,
+  loading: false,
+  round: true,
+  toolbarConfig: {
+    slots: {
+      buttons: 'toolbar_buttons',
+    },
+    refresh: true,
+  },
+
+  rowConfig: {
+    isHover: true,
+  },
+  columnConfig: {
+    resizable: true,
+  },
+  pagerConfig: {
+    enabled: true,
+    total: 20,
+    currentPage: 1,
+    pageSize: 10,
+    pageSizes: [10, 20, 30],
+  },
+  editConfig: {
+    trigger: 'auto',
+    mode: 'row',
+    showStatus: true,
+  },
+  checkboxConfig: {
+    reserve: true,
+    highlight: true,
+    range: true,
+  },
+  columns: [
+    {type: 'checkbox', width: 50},
+    {type: 'seq', title: 'ID', width: 120},
+    {
+      field: 'platformNumber',
+      title: '平台编号',
+      editRender: {autofocus: '.vxe-input--inner'},
+      slots: {edit: 'number_edit'},
+      sortable: true,
+    },
+    {
+      field: 'platformName',
+      title: '平台名称',
+      editRender: {autofocus: '.vxe-input--inner'},
+      slots: {edit: 'name_edit'}
+    },
+    {field: 'country', title: '国家', editRender: {autofocus: '.vxe-input--inner'}, slots: {edit: 'country_edit'}},
+    {field: 'brandName', title: '品牌', editRender: {}, slots: {edit: 'brand_edit'}},
+    {field: 'user_name', title: '运营', editRender: {}, slots: {edit: 'operation_edit'}},
+    {field: 'currencyCode', title: '汇款币种', editRender: {}, slots: {edit: 'currency_edit'}},
+    {field: 'child_user_number', title: '录入人员数', editRender: {}, slots: {edit: 'quantity_edit'}},
+    {title: '操作', width: 300, slots: {default: 'operate'}},
+  ],
+  data: [],
+})
+
+const operationList = ref([
+  {value: '1', label: 'option1'},
+  {value: '2', label: 'option2'},
+])
+const quantityList = ref([
+  {value: '1', label: 'per1'},
+  {value: '2', label: 'per2'},
+])
+
+// 分页
+const gridEvents: VxeGridListeners<RowVO> = {
+  pageChange({currentPage, pageSize}) {
+    // console.log(currentPage, pageSize)
+    if (gridOptions.pagerConfig) {
+      gridOptions.pagerConfig.currentPage = currentPage
+      gridOptions.pagerConfig.pageSize = pageSize
+      getTaskList()
+    }
+  },
+}
+
+async function getTaskList() {
+  const resp = await getTasks({
+    page: gridOptions.pagerConfig.currentPage,
+    limit: gridOptions.pagerConfig.pageSize
+  })
+  gridOptions.data = resp.data
+  gridOptions.pagerConfig.total = resp.total
+}
+
+/**
+ * 判断当前编辑行
+ * @param {RowVO} row 当前行
+ * @return {boolean}
+ */
+const hasActiveEditRow = (row: RowVO) => {
+  const $grid = xGrid.value
+  if ($grid) {
+    return $grid.isEditByRow(row)
+  }
+  return false
+}
+
+const editRowEvent = (row: RowVO) => {
+  const $grid = xGrid.value
+  if ($grid) {
+    $grid.setEditRow(row)
+    console.log(row.id)
+  }
+}
+
+//清除编辑状态
+const clearRowEvent = () => {
+  const $grid = xGrid.value
+  if ($grid) {
+    $grid.clearEdit()
+  }
+}
+
+// 删除选中行
+const removeEvent = async () => {
+  const $grid = xGrid.value
+  if ($grid) {
+    const selectRecords = $grid.getCheckboxRecords()
+    if (selectRecords.length > 0) {
+      const type = await VXETable.modal.confirm('您确定要删除选中的数据?')
+      if (type === 'confirm') {
+        await $grid.removeCheckboxRow()
+      }
+    } else {
+      await VXETable.modal.message({content: '请选择要删除的数据', status: 'error'})
+    }
+  }
+}
+
+// let n = setEditRow(row.id)
+async function updateRow() {
+  const body = {
+    country:gridOptions.data[0].country,
+    platformNumber:gridOptions.data[0].platformNumber,
+    platformName:gridOptions.data[0].platformName,
+    brandName:gridOptions.data[0].brandName,
+    user:gridOptions.data[0].operation,
+    currencyCode:gridOptions.data[0].currencyCode,
+  }
+  try {
+    const response = await postUpdateTask(body)
+    console.log(response.data)
+    if (response.data.code === 'success') {
+      ElMessage.success('更新成功')
+    } else if (response.data.code === 'error') {
+      ElMessage.warning(`${response.data.description}`)
+    } else {
+      ElMessage.error('更新失败')
+    }
+  } catch (error) {
+    console.error('error:', error)
+  }
+}
+// 保存表格行数据
+const saveRowEvent = async (row: RowVO) => {
+  const $grid = xGrid.value
+  if ($grid) {
+    // await updateRow()
+    console.log(gridOptions.data[0].id)
+    await $grid.clearEdit()
+    gridOptions.loading = true
+    setTimeout(() => {
+      gridOptions.loading = false
+    }, 300)
+  }
+}
+
+// 保存全部数据
+const saveEvent = async () => {
+  const $grid = xGrid.value
+  if ($grid) {
+    const {insertRecords, removeRecords, updateRecords} = $grid.getRecordset()
+    await VXETable.modal.message({
+      content: `新增 ${insertRecords.length} 条,删除 ${removeRecords.length} 条,更新 ${updateRecords.length} 条`,
+      status: 'success',
+    })
+  }
+}
+
+async function createTask() {
+  const body = {
+    country: taskRuleForm.country,
+    platformNumber: taskRuleForm.number,
+    platformName: taskRuleForm.name,
+    brandName: taskRuleForm.brand,
+    currencyCode: taskRuleForm.currency,
+    user: [taskRuleForm.operation],
+  }
+  try {
+    const resp = await postCreateTask(body) // await VXETable.modal.message({ content: '创建成功', status: 'success' })
+  } catch (error) {
+    console.error('error:', error)
+    await VXETable.modal.message({content: '创建失败,请重试', status: 'error'})
+  }
+}
+
+// 新建任务
+const submitEvent = async () => {
+
+  // 创建一个新的行对象,用于保存表单数据
+  const newRow: RowVO = {
+    platformNumber: taskRuleForm.number,
+    platformName: taskRuleForm.name,
+    country: taskRuleForm.country,
+    brandName: taskRuleForm.brand,
+    user_name: taskRuleForm.operation,
+    currencyCode: taskRuleForm.currency,
+    child_user_number: '',
+  }
+  // 将新行添加到表格数据中
+  gridOptions.data.push(newRow)
+  try {
+    await createTask()
+    dialogFormVisible.value = false
+    //获取更新表格数据
+    await saveEvent()
+    await getTaskList()
+    await nextTick(() => {
+      loading.value = true
+      setTimeout(() => {
+        loading.value = false
+      }, 500)
+    })
+  } catch (error) {
+    console.error('Failed to save task:', error)
+  }
+}
+
+// 提交表单
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate(async (valid, fields) => {
+    if (valid) {
+      await submitEvent();
+      await nextTick();
+      taskRuleFormRef.value.resetFields();
+    } else {
+      console.log('error submit!', fields)
+    }
+  });
+};
+
+
+async function fetchOperationSelect() {
+  try {
+    const resp = await getOperationSelect()
+    // console.log("resp", resp.data)
+    operationList.value = resp.data.map((item: any) => {
+      return {value: item.id, label: item.name}
+    })
+    // console.log(operationList.value)
+  } catch (e) {
+    console.error("Failed to fetch operation select:", e)
+  }
+}
+
+// async function fetchQuantitySelect() {
+//   try {
+//     const resp = await getQuantitySelect()
+//     quantityList.value = resp.data.map((item: any) => {
+//       return {value: item.id, label: item.name}
+//     })
+//   } catch (e) {
+//     console.error("Failed to fetch operation select:", e)
+//   }
+// }
+
+onMounted(() => {
+  getTaskList()
+  fetchOperationSelect()
+})
 </script>
 
 <template>
+  <el-card class="custom-card-style flex gap-1.5 justify-between my-1.5 mx-2">
+    <Selector></Selector>
+  </el-card>
+  <el-card class="mx-2">
+    <div style="position: relative">
+      <vxe-grid ref="xGrid" v-bind="gridOptions" v-on="gridEvents" v-loading="loading">
+        <template #toolbar_buttons>
+          <vxe-button icon="vxe-icon-add" plain @click="dialogFormVisible = true"> 添加任务</vxe-button>
+          <vxe-button icon="vxe-icon-delete" @click="removeEvent">删除</vxe-button>
+          <vxe-button icon="vxe-icon-save" @click="saveEvent">保存</vxe-button>
+        </template>
+        <template #operate="{ row }">
+          <template v-if="hasActiveEditRow(row)">
+            <vxe-button content="取消" @click="clearRowEvent"></vxe-button>
+            <vxe-button status="primary" content="保存" @click="saveRowEvent(row)"></vxe-button>
+          </template>
+          <template v-else>
+            <vxe-button content="编辑" @click="editRowEvent(row)"></vxe-button>
+          </template>
+        </template>
 
+        <template #number_edit="{ row }">
+          <vxe-input v-model="row.platformNumber"></vxe-input>
+        </template>
+        <template #name_edit="{ row }">
+          <vxe-input v-model="row.platformName"></vxe-input>
+        </template>
+        <template #country_edit="{ row }">
+          <vxe-input v-model="row.country"></vxe-input>
+        </template>
+        <template #brand_edit="{ row }">
+          <vxe-input v-model="row.brandName"></vxe-input>
+        </template>
+        <template #operation_edit="{ row }">
+          <vxe-select v-model="row.user_name" transfer>
+            <vxe-option v-for="item in operationList" :key="item.value" :value="item.value" :label="item.label"></vxe-option>
+          </vxe-select>
+        </template>
+        <template #currency_edit="{ row }">
+          <vxe-input v-model="row.currencyCode"></vxe-input>
+        </template>
+        <template #quantity_edit="{ row }">
+          <vxe-select v-model="row.child_user_number" transfer>
+            <vxe-option v-for="item in quantityList" :key="item.value" :value="item.value" :label="item.label"></vxe-option>
+          </vxe-select>
+        </template>
+      </vxe-grid>
+    </div>
+  </el-card>
+  <el-dialog v-model="dialogFormVisible" title="新建任务" width="500">
+    <el-form
+      ref="taskRuleFormRef"
+      style="max-width: 600px"
+      :model="taskRuleForm"
+      :rules="rules"
+      label-width="auto"
+      class="demo-taskRuleForm"
+      :size="formSize"
+      status-icon>
+      <el-form-item label="平台编号" prop="number">
+        <el-input v-model="taskRuleForm.number" placeholder="请输入平台编号" />
+      </el-form-item>
+      <el-form-item label="平台名称" prop="name">
+        <el-input v-model="taskRuleForm.name" placeholder="请输入平台名称" />
+      </el-form-item>
+      <el-form-item label="国家" prop="country">
+        <el-input v-model="taskRuleForm.country" placeholder="请输入国家" />
+      </el-form-item>
+      <el-form-item label="品牌" prop="brand">
+        <el-input v-model="taskRuleForm.brand" placeholder="请输入品牌" />
+      </el-form-item>
+      <el-form-item label="运营" prop="operation">
+        <el-select v-model="taskRuleForm.operation" placeholder="请选择运营">
+          <el-option v-for="item in operationList" :key="item.value" :value="item.value" :label="item.label"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="回款币种" prop="currency">
+        <el-input v-model="taskRuleForm.currency" placeholder="请输入回款币种" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="dialogFormVisible = false ;resetForm(taskRuleFormRef)">取消</el-button>
+        <el-button type="primary" @click="submitForm(taskRuleFormRef)"> 确认</el-button>
+      </div>
+    </template>
+  </el-dialog>
 </template>
 
 <style scoped>
-
-</style>
+.custom-card-style {
+  z-index: 999;
+  position: sticky;
+  top: 0;
+}
+</style>