li.shaoyi 8 月之前
父節點
當前提交
50e213cf4a
共有 35 個文件被更改,包括 1381 次插入360 次删除
  1. 48 3
      src/filters/index.ts
  2. 3 3
      src/packages/mobile/components/modules/trade/index.vue
  3. 1 1
      src/packages/mobile/views/cart/detail/index.vue
  4. 3 1
      src/packages/pc/assets/themes/global/global.less
  5. 2 8
      src/packages/pc/views/investor/manage/cancelapply/components/details/index.vue
  6. 18 19
      src/packages/pc/views/investor/manage/user/components/details/view.vue
  7. 14 37
      src/packages/pc/views/investor/manage/user/components/edit/index.vue
  8. 7 10
      src/packages/pc/views/investor/user/open/components/details/index.vue
  9. 11 34
      src/packages/pc/views/investor/user/open/components/edit/index.vue
  10. 19 19
      src/packages/pc/views/member/institution/open/components/details/index.vue
  11. 13 36
      src/packages/pc/views/member/institution/open/components/edit/index.vue
  12. 17 19
      src/packages/pc/views/member/institution/user/components/details/index.vue
  13. 46 56
      src/packages/pc/views/member/institution/user/components/edit/index.vue
  14. 3 4
      src/packages/pc/views/member/institution/user/index.vue
  15. 13 16
      src/packages/pc/views/member/subinstitution/manage/components/details/index.vue
  16. 13 36
      src/packages/pc/views/member/subinstitution/manage/components/edit/index.vue
  17. 82 0
      src/packages/pc/views/notice/manage/components/audit/index.vue
  18. 52 0
      src/packages/pc/views/notice/manage/components/delete/index.vue
  19. 22 8
      src/packages/pc/views/notice/manage/components/details/index.vue
  20. 58 29
      src/packages/pc/views/notice/manage/components/edit/index.vue
  21. 56 0
      src/packages/pc/views/notice/manage/components/forced/index.vue
  22. 33 7
      src/packages/pc/views/notice/manage/index.vue
  23. 55 0
      src/packages/pc/views/notice/newscolumn/components/delete/index.vue
  24. 58 0
      src/packages/pc/views/notice/newscolumn/components/details/index.vue
  25. 115 0
      src/packages/pc/views/notice/newscolumn/components/edit/index.vue
  26. 97 1
      src/packages/pc/views/notice/newscolumn/index.vue
  27. 52 0
      src/packages/pc/views/notice/newssource/components/delete/index.vue
  28. 56 0
      src/packages/pc/views/notice/newssource/components/details/index.vue
  29. 104 0
      src/packages/pc/views/notice/newssource/components/edit/index.vue
  30. 86 1
      src/packages/pc/views/notice/newssource/index.vue
  31. 7 4
      src/packages/pc/views/query/internal/offlinedelivery/components/details/index.vue
  32. 5 2
      src/packages/pc/views/query/internal/offlinedelivery/index.vue
  33. 87 3
      src/services/api/notice/index.ts
  34. 122 3
      src/types/model/notice.d.ts
  35. 3 0
      src/types/model/order.d.ts

+ 48 - 3
src/filters/index.ts

@@ -1,5 +1,7 @@
-import moment from 'moment'
+import { UploadUserFile } from 'element-plus'
 import { Decimal } from 'decimal.js'
+import moment from 'moment'
+import service from '@/services'
 
 /**
  * 日期格式化
@@ -19,9 +21,9 @@ export function formatDate(value?: string, format = 'YYYY-MM-DD HH:mm:ss') {
  */
 export function handlePriceColor(curValue: number, preValue: number) {
     if (!curValue || curValue === preValue) {
-        return '';
+        return ''
     } else if (curValue > preValue) {
-        return 'g-color--up';
+        return 'g-color--up'
     } else {
         return 'g-color--down'
     }
@@ -234,4 +236,47 @@ export function parseTenThousand(value = 0, decimal = 2, round = false) {
     const num = new Decimal(value).times(10000)
     const res = formatDecimal(num.toNumber(), decimal, round)
     return res + '‱'
+}
+
+/**
+ * 转换文件路径
+ * @param value 
+ * @returns 
+ */
+export function parseFilePaths(value?: string) {
+    const paths = value ? value.split(',') : []
+    return paths.map((url) => {
+        const urlObj = new URL(url, service.getConfig('apiUrl'))
+        const name = urlObj.pathname.split('/').pop()
+        return {
+            name: name ?? urlObj.href,
+            url: urlObj.href,
+            response: {
+                data: [{ filePath: value }]
+            }
+        }
+    })
+}
+
+/**
+ * 提取文件路径
+ * @param uploadFiles 
+ * @returns 
+ */
+export function extractFilePaths(uploadFiles: UploadUserFile[]) {
+    return uploadFiles.map((e) => {
+        const res = e.response as { data: { filePath: string }[] }
+        return res.data.map((e) => e.filePath)
+    }).join(',')
+}
+
+/**
+ * 获取首路径完整 Url
+ * @param path 
+ * @returns 
+ */
+export function getFirstPathFullUrl(path?: string) {
+    const baseUrl = service.getConfig('apiUrl')
+    const paths = path?.split(',')
+    return paths?.length ? new URL(paths[0], baseUrl).href : ''
 }

+ 3 - 3
src/packages/mobile/components/modules/trade/index.vue

@@ -2,7 +2,7 @@
     <app-modal class="app-trade" direction="right" height="100%" v-model:show="showModal">
         <div class="app-trade__wrapper">
             <div class="app-trade__header">
-                <app-navbar title="挂牌求购" @back="closed" />
+                <app-navbar title="挂牌求购" @back="close" />
             </div>
             <div class="app-trade__body">
                 <AddressEdit show-postal show-delete show-set-default show-search-result
@@ -20,13 +20,13 @@ import AppModal from '@/components/base/modal/index.vue'
 const showModal = ref(true);
 
 // 关闭弹窗
-const closed = () => {
+const close = () => {
     showModal.value = false;
 }
 
 // 暴露组件属性给父组件调用
 defineExpose({
-    closed,
+    close,
 })
 </script>
 

+ 1 - 1
src/packages/mobile/views/cart/detail/index.vue

@@ -46,7 +46,7 @@ const tabChange = (index: number) => {
 
 onBeforeRouteLeave((to, from, next) => {
   if (componentId.value) {
-    childComponent.value?.closed(); // 调用子组件方法
+    childComponent.value?.close(); // 调用子组件方法
     next(false);
   } else {
     next();

+ 3 - 1
src/packages/pc/assets/themes/global/global.less

@@ -77,8 +77,10 @@
 }
 
 .g-text-message {
+    display: flex;
+    flex-direction: column;
     font-size: 16px;
-    line-height: normal;
+    line-height: 1.5;
 }
 
 .g-view-tree {

+ 2 - 8
src/packages/pc/views/investor/manage/cancelapply/components/details/index.vue

@@ -4,7 +4,7 @@
         <app-table-details :data="data" :label-width="120" :cell-props="detailProps" :column="2">
             <!-- 确认半身照 -->
             <template #imageurl="{ value }">
-                <el-image :src="getImageUrl(value)" fit="cover" lazy style="width: 128px; height: 72px" />
+                <el-image :src="getFirstPathFullUrl(value)" fit="cover" lazy style="width: 128px; height: 72px" />
             </template>
         </app-table-details>
         <template #footer>
@@ -16,14 +16,13 @@
 <script lang="ts" setup>
 import { shallowRef, PropType, computed } from 'vue'
 import { ElMessage } from 'element-plus'
-import { formatDate } from '@/filters'
+import { formatDate, getFirstPathFullUrl } from '@/filters'
 import { useEnum } from '@/hooks/enum'
 import { useRequest } from '@/hooks/request'
 import { investorCancelview } from '@/services/api/investor'
 import { CellProp } from '@pc/components/base/table-details/types'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import AppTableDetails from '@pc/components/base/table-details/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -58,11 +57,6 @@ const detailProps = computed<CellProp[]>(() => [
     { prop: 'imageurl', label: 'investor.manage.cancelapply.details.imageurl' },
 ])
 
-const getImageUrl = (path: string) => {
-    const baseUrl = service.getConfig('apiUrl')
-    return path && new URL(path, baseUrl).href
-}
-
 const onCancel = () => {
     show.value = false
 }

+ 18 - 19
src/packages/pc/views/investor/manage/user/components/details/view.vue

@@ -1,6 +1,7 @@
 <!-- 交易商管理-交易商管理-交易商管理-详情 -->
 <template>
-    <app-drawer :title="t('investor.manage.user.details.title')" width="900" v-model:show="show" :loading="loading" :refresh="refresh">
+    <app-drawer :title="t('investor.manage.user.details.title')" width="900" v-model:show="show" :loading="loading"
+        :refresh="refresh">
         <app-table-details :title="t('common.baseinfo')" :data="oldData?.userAccountDetailVo" :label-width="160"
             :cell-props="detailProps1" :column="2">
             <!-- 交易商名称 -->
@@ -20,7 +21,8 @@
                 <span v-else>{{ oldData?.userAccountDetailVo.accountName }}</span>
             </template>
         </app-table-details>
-        <app-table-details :title="oldData?.userinfoDetailVo.userinfoType === UserInfoType.Personal ? t('investor.manage.user.details.subtitle1') : t('investor.manage.user.details.subtitle2')"
+        <app-table-details
+            :title="oldData?.userinfoDetailVo.userinfoType === UserInfoType.Personal ? t('investor.manage.user.details.subtitle1') : t('investor.manage.user.details.subtitle2')"
             :data="oldData?.userinfoDetailVo" :label-width="160" :cell-props="detailProps2" :column="2">
             <!-- 证件照正面 -->
             <template #cardFrontPhotoUrl="{ value }">
@@ -56,7 +58,7 @@
 
 <script lang="ts" setup>
 import { ref, computed } from 'vue'
-import { handleNoneValue, formatDate } from '@/filters'
+import { handleNoneValue, formatDate, getFirstPathFullUrl } from '@/filters'
 import { decryptAES } from '@/services/crypto'
 import { useEnum } from '@/hooks/enum'
 import { UserInfoType, getGenderName } from '@/constants/member'
@@ -65,7 +67,6 @@ import { queryInvestorListDetail } from '@/services/api/investor'
 import { CellProp } from '@pc/components/base/table-details/types'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import AppTableDetails from '@pc/components/base/table-details/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -107,17 +108,15 @@ useRequest(queryInvestorListDetail, {
     },
     onSuccess: (res) => {
         const { newResult, oldResult } = res.data
-        const baseUrl = service.getConfig('apiUrl')
-        const getUrl = (value: string) => value && new URL(value, baseUrl).href
-
+        
         if (newResult) {
             const detail = newResult.userinfoDetailVo
-            detail.cardFrontPhotoUrl = getUrl(detail.cardFrontPhotoUrl)
-            detail.cardBackPhotoUrl = getUrl(detail.cardBackPhotoUrl)
-            detail.halfBodyPhotoUrl = getUrl(detail.halfBodyPhotoUrl)
-            detail.legalCardFrontPhotoUrl = getUrl(detail.legalCardFrontPhotoUrl)
-            detail.legalCardBackPhotoUrl = getUrl(detail.legalCardBackPhotoUrl)
-            detail.otherUrl = getUrl(detail.otherUrl)
+            detail.cardFrontPhotoUrl = getFirstPathFullUrl(detail.cardFrontPhotoUrl)
+            detail.cardBackPhotoUrl = getFirstPathFullUrl(detail.cardBackPhotoUrl)
+            detail.halfBodyPhotoUrl = getFirstPathFullUrl(detail.halfBodyPhotoUrl)
+            detail.legalCardFrontPhotoUrl = getFirstPathFullUrl(detail.legalCardFrontPhotoUrl)
+            detail.legalCardBackPhotoUrl = getFirstPathFullUrl(detail.legalCardBackPhotoUrl)
+            detail.otherUrl = getFirstPathFullUrl(detail.otherUrl)
 
             detail.cardNum = decryptAES(detail.cardNum)
             detail.mobile = decryptAES(detail.mobile)
@@ -127,12 +126,12 @@ useRequest(queryInvestorListDetail, {
         }
         if (oldResult) {
             const detail = oldResult.userinfoDetailVo
-            detail.cardFrontPhotoUrl = getUrl(detail.cardFrontPhotoUrl)
-            detail.cardBackPhotoUrl = getUrl(detail.cardBackPhotoUrl)
-            detail.halfBodyPhotoUrl = getUrl(detail.halfBodyPhotoUrl)
-            detail.legalCardFrontPhotoUrl = getUrl(detail.legalCardFrontPhotoUrl)
-            detail.legalCardBackPhotoUrl = getUrl(detail.legalCardBackPhotoUrl)
-            detail.otherUrl = getUrl(detail.otherUrl)
+            detail.cardFrontPhotoUrl = getFirstPathFullUrl(detail.cardFrontPhotoUrl)
+            detail.cardBackPhotoUrl = getFirstPathFullUrl(detail.cardBackPhotoUrl)
+            detail.halfBodyPhotoUrl = getFirstPathFullUrl(detail.halfBodyPhotoUrl)
+            detail.legalCardFrontPhotoUrl = getFirstPathFullUrl(detail.legalCardFrontPhotoUrl)
+            detail.legalCardBackPhotoUrl = getFirstPathFullUrl(detail.legalCardBackPhotoUrl)
+            detail.otherUrl = getFirstPathFullUrl(detail.otherUrl)
 
             detail.cardNum = decryptAES(detail.cardNum)
             detail.mobile = decryptAES(detail.mobile)

+ 14 - 37
src/packages/pc/views/investor/manage/user/components/edit/index.vue

@@ -79,7 +79,8 @@
                         :placeholder="t('common.pleaseenter')" />
                 </el-form-item>
                 <el-form-item class="el-form-item--row" :label="t('investor.manage.user.edit.region')" prop="region">
-                    <app-region class="el-form-item--col" v-model:country="formData.userinfoDetailVo.countryid" v-model:province="formData.userinfoDetailVo.provinceid"
+                    <app-region class="el-form-item--col" v-model:country="formData.userinfoDetailVo.countryid"
+                        v-model:province="formData.userinfoDetailVo.provinceid"
                         v-model:city="formData.userinfoDetailVo.cityid"
                         v-model:district="formData.userinfoDetailVo.districtid" />
                 </el-form-item>
@@ -149,7 +150,7 @@
 <script lang="ts" setup>
 import { ref, reactive, PropType, onMounted, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules, UploadUserFile } from 'element-plus'
-import { handleNoneValue } from '@/filters'
+import { handleNoneValue, parseFilePaths, extractFilePaths } from '@/filters'
 import { useRequest } from '@/hooks/request'
 import { investorEdit, queryInvestorListDetail } from '@/services/api/investor'
 import { getUserInfoTypeList, getGenderList, UserInfoType } from '@/constants/member'
@@ -158,7 +159,6 @@ import AppUpload from '@pc/components/base/upload/index.vue'
 import AppEnum from '@pc/components/modules/enum/index.vue'
 import AppRegion from '@pc/components/modules/region/index.vue'
 import AppSelectMember from '@pc/components/modules/select-member/index.vue'
-import service from '@/services'
 import { decryptAES } from '@/services/crypto'
 import { i18n } from '@/stores'
 
@@ -199,21 +199,6 @@ const formData = ref<Investor.InvestorEditReq>({
     userinfoDetailVo: {}
 })
 
-const getUploadFiles = (value?: string) => {
-    const paths = value ? value.split(',') : []
-    return paths.map((url) => {
-        const urlObj = new URL(url, service.getConfig('apiUrl'))
-        const name = urlObj.pathname.split('/').pop()
-        return {
-            name: name ?? urlObj.href,
-            url: urlObj.href,
-            response: {
-                data: [{ filePath: value }]
-            }
-        }
-    })
-}
-
 const { loading, run } = useRequest(queryInvestorListDetail, {
     manual: true,
     onSuccess: ((res) => {
@@ -225,11 +210,11 @@ const { loading, run } = useRequest(queryInvestorListDetail, {
         userinfoDetailVo.wechat = decryptAES(userinfoDetailVo.wechat)
         userinfoDetailVo.email = decryptAES(userinfoDetailVo.email)
 
-        uploadFiles.cardFrontPhotoUrl = getUploadFiles(userinfoDetailVo.cardFrontPhotoUrl)
-        uploadFiles.cardBackPhotoUrl = getUploadFiles(userinfoDetailVo.cardBackPhotoUrl)
-        uploadFiles.legalCardFrontPhotoUrl = getUploadFiles(userinfoDetailVo.legalCardFrontPhotoUrl)
-        uploadFiles.legalCardBackPhotoUrl = getUploadFiles(userinfoDetailVo.legalCardBackPhotoUrl)
-        uploadFiles.otherUrl = getUploadFiles(userinfoDetailVo.otherUrl)
+        uploadFiles.cardFrontPhotoUrl = parseFilePaths(userinfoDetailVo.cardFrontPhotoUrl)
+        uploadFiles.cardBackPhotoUrl = parseFilePaths(userinfoDetailVo.cardBackPhotoUrl)
+        uploadFiles.legalCardFrontPhotoUrl = parseFilePaths(userinfoDetailVo.legalCardFrontPhotoUrl)
+        uploadFiles.legalCardBackPhotoUrl = parseFilePaths(userinfoDetailVo.legalCardBackPhotoUrl)
+        uploadFiles.otherUrl = parseFilePaths(userinfoDetailVo.otherUrl)
 
         formData.value = res.data.oldResult
         parentuseridRef.value.onReset(userAccountDetailVo.parentuserid)
@@ -261,23 +246,15 @@ const onCancel = (isRefresh = false) => {
     refresh.value = isRefresh
 }
 
-// 更新上传文件到表单中
-const updateUploadFiles = (uploadFiles: UploadUserFile[]) => {
-    return uploadFiles.map((e) => {
-        const res = e.response as { data: { filePath: string }[] }
-        return res.data.map((e) => e.filePath)
-    }).join(',')
-}
-
 const onSubmit = () => {
     const rawData = { ...formData.value }
     rawData.userAccountDetailVo.modifyStatus = 3
-    rawData.userinfoDetailVo.cardFrontPhotoUrl = updateUploadFiles(uploadFiles.cardFrontPhotoUrl)
-    rawData.userinfoDetailVo.cardBackPhotoUrl = updateUploadFiles(uploadFiles.cardBackPhotoUrl)
-    rawData.userinfoDetailVo.halfBodyPhotoUrl = updateUploadFiles(uploadFiles.halfBodyPhotoUrl)
-    rawData.userinfoDetailVo.legalCardFrontPhotoUrl = updateUploadFiles(uploadFiles.legalCardFrontPhotoUrl)
-    rawData.userinfoDetailVo.legalCardBackPhotoUrl = updateUploadFiles(uploadFiles.legalCardBackPhotoUrl)
-    rawData.userinfoDetailVo.otherUrl = updateUploadFiles(uploadFiles.otherUrl)
+    rawData.userinfoDetailVo.cardFrontPhotoUrl = extractFilePaths(uploadFiles.cardFrontPhotoUrl)
+    rawData.userinfoDetailVo.cardBackPhotoUrl = extractFilePaths(uploadFiles.cardBackPhotoUrl)
+    rawData.userinfoDetailVo.halfBodyPhotoUrl = extractFilePaths(uploadFiles.halfBodyPhotoUrl)
+    rawData.userinfoDetailVo.legalCardFrontPhotoUrl = extractFilePaths(uploadFiles.legalCardFrontPhotoUrl)
+    rawData.userinfoDetailVo.legalCardBackPhotoUrl = extractFilePaths(uploadFiles.legalCardBackPhotoUrl)
+    rawData.userinfoDetailVo.otherUrl = extractFilePaths(uploadFiles.otherUrl)
 
     formRef.value?.validate((valid) => {
         if (valid) {

+ 7 - 10
src/packages/pc/views/investor/user/open/components/details/index.vue

@@ -44,6 +44,7 @@
 <script lang="ts" setup>
 import { shallowRef, PropType, computed } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
+import { getFirstPathFullUrl } from '@/filters'
 import { decryptAES } from '@/services/crypto'
 import { getUserInfoTypeName, getGenderName, UserInfoType } from '@/constants/member'
 import { useEnum } from '@/hooks/enum'
@@ -52,7 +53,6 @@ import { queryInvestorDetail, investorProcess } from '@/services/api/investor'
 import { CellProp } from '@pc/components/base/table-details/types'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import AppTableDetails from '@pc/components/base/table-details/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -78,15 +78,12 @@ const { data } = useRequest(queryInvestorDetail, {
     },
     onSuccess: () => {
         if (data.value) {
-            const baseUrl = service.getConfig('apiUrl')
-            const getUrl = (value: string) => value && new URL(value, baseUrl).href
-
-            data.value.cardfrontphotourl = getUrl(data.value.cardfrontphotourl)
-            data.value.cardbackphotourl = getUrl(data.value.cardbackphotourl)
-            data.value.halfbodyphotourl = getUrl(data.value.halfbodyphotourl)
-            data.value.legalcardfrontphotourl = getUrl(data.value.legalcardfrontphotourl)
-            data.value.legalcardbackphotourl = getUrl(data.value.legalcardbackphotourl)
-            data.value.otherurl = getUrl(data.value.otherurl)
+            data.value.cardfrontphotourl = getFirstPathFullUrl(data.value.cardfrontphotourl)
+            data.value.cardbackphotourl = getFirstPathFullUrl(data.value.cardbackphotourl)
+            data.value.halfbodyphotourl = getFirstPathFullUrl(data.value.halfbodyphotourl)
+            data.value.legalcardfrontphotourl = getFirstPathFullUrl(data.value.legalcardfrontphotourl)
+            data.value.legalcardbackphotourl = getFirstPathFullUrl(data.value.legalcardbackphotourl)
+            data.value.otherurl = getFirstPathFullUrl(data.value.otherurl)
         }
     },
     onError: (err) => {

+ 11 - 34
src/packages/pc/views/investor/user/open/components/edit/index.vue

@@ -147,6 +147,7 @@
 <script lang="ts" setup>
 import { ref, reactive, PropType, onMounted, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules, UploadUserFile } from 'element-plus'
+import { parseFilePaths, extractFilePaths } from '@/filters'
 import { decryptAES } from '@/services/crypto'
 import { useRequest } from '@/hooks/request'
 import { dealSunOrgan, queryInvestorDetail } from '@/services/api/investor'
@@ -158,7 +159,6 @@ import AppEnum from '@pc/components/modules/enum/index.vue'
 import AppRegion from '@pc/components/modules/region/index.vue'
 import AppSelectMember from '@pc/components/modules/select-member/index.vue'
 import AppSelectInvestor from '@pc/components/modules/select-investor/index.vue'
-import service from '@/services'
 
 const props = defineProps({
     record: {
@@ -203,21 +203,6 @@ const parentuseridfirst = computed(() => formData.value.areaid || userStore.user
 // 是否个人
 const isPerson = computed(() => formData.value.userinfotype === UserInfoType.Personal)
 
-const getUploadFiles = (value?: string) => {
-    const paths = value ? value.split(',') : []
-    return paths.map((url) => {
-        const urlObj = new URL(url, service.getConfig('apiUrl'))
-        const name = urlObj.pathname.split('/').pop()
-        return {
-            name: name ?? urlObj.href,
-            url: urlObj.href,
-            response: {
-                data: [{ filePath: value }]
-            }
-        }
-    })
-}
-
 const { loading, run } = useRequest(queryInvestorDetail, {
     manual: true,
     onSuccess: ((res) => {
@@ -228,11 +213,11 @@ const { loading, run } = useRequest(queryInvestorDetail, {
         res.data.email = decryptAES(res.data.email)
         formData.value = res.data
 
-        uploadFiles.cardfrontphotourl = getUploadFiles(res.data.cardfrontphotourl)
-        uploadFiles.cardbackphotourl = getUploadFiles(res.data.cardbackphotourl)
-        uploadFiles.legalcardfrontphotourl = getUploadFiles(res.data.legalcardfrontphotourl)
-        uploadFiles.legalcardbackphotourl = getUploadFiles(res.data.legalcardbackphotourl)
-        uploadFiles.otherurl = getUploadFiles(res.data.otherurl)
+        uploadFiles.cardfrontphotourl = parseFilePaths(res.data.cardfrontphotourl)
+        uploadFiles.cardbackphotourl = parseFilePaths(res.data.cardbackphotourl)
+        uploadFiles.legalcardfrontphotourl = parseFilePaths(res.data.legalcardfrontphotourl)
+        uploadFiles.legalcardbackphotourl = parseFilePaths(res.data.legalcardbackphotourl)
+        uploadFiles.otherurl = parseFilePaths(res.data.otherurl)
 
         memberareaidRef.value?.onReset(res.data.memberareaid)
         areaidRef.value.onReset(res.data.areaid)
@@ -322,22 +307,14 @@ const onCancel = (isRefresh = false) => {
     refresh.value = isRefresh
 }
 
-// 更新上传文件到表单中
-const updateUploadFiles = (uploadFiles: UploadUserFile[]) => {
-    return uploadFiles.map((e) => {
-        const res = e.response as { data: { filePath: string }[] }
-        return res.data.map((e) => e.filePath)
-    }).join(',')
-}
-
 const onSubmit = () => {
     const rawData = { ...formData.value }
     rawData.userstate = 2
-    rawData.cardfrontphotourl = updateUploadFiles(uploadFiles.cardfrontphotourl)
-    rawData.cardbackphotourl = updateUploadFiles(uploadFiles.cardbackphotourl)
-    rawData.legalcardfrontphotourl = updateUploadFiles(uploadFiles.legalcardfrontphotourl)
-    rawData.legalcardbackphotourl = updateUploadFiles(uploadFiles.legalcardbackphotourl)
-    rawData.otherurl = updateUploadFiles(uploadFiles.otherurl)
+    rawData.cardfrontphotourl = extractFilePaths(uploadFiles.cardfrontphotourl)
+    rawData.cardbackphotourl = extractFilePaths(uploadFiles.cardbackphotourl)
+    rawData.legalcardfrontphotourl = extractFilePaths(uploadFiles.legalcardfrontphotourl)
+    rawData.legalcardbackphotourl = extractFilePaths(uploadFiles.legalcardbackphotourl)
+    rawData.otherurl = extractFilePaths(uploadFiles.otherurl)
 
     formRef.value?.validate((valid) => {
         if (valid) {

+ 19 - 19
src/packages/pc/views/member/institution/open/components/details/index.vue

@@ -1,14 +1,16 @@
 <!-- 会员机构管理-机构管理-机构开户申请-详情 -->
 <template>
-    <app-drawer :title="t('member.institution.open.details.title')" width="900" v-model:show="show" :loading="loading" :refresh="refresh">
-        <app-table-details :title="t('common.baseinfo')" :data="data" :label-width="160" :cell-props="detailProps1" :column="2">
+    <app-drawer :title="t('member.institution.open.details.title')" width="900" v-model:show="show" :loading="loading"
+        :refresh="refresh">
+        <app-table-details :title="t('common.baseinfo')" :data="data" :label-width="160" :cell-props="detailProps1"
+            :column="2">
             <!-- 创建时间 -->
             <template #createtime="{ value }">
                 {{ formatDate(value) }}
             </template>
         </app-table-details>
-        <app-table-details :title="t('member.institution.open.details.subtitle1')" :data="data" :label-width="160" :cell-props="detailProps2" :column="2"
-            v-if="isPerson">
+        <app-table-details :title="t('member.institution.open.details.subtitle1')" :data="data" :label-width="160"
+            :cell-props="detailProps2" :column="2" v-if="isPerson">
             <!-- 证件类型 -->
             <template #cardtype="{ value }">
                 {{ certypepersonEnum.getEnumTypeName(value) }}
@@ -22,7 +24,8 @@
                 <el-image :src="value" fit="cover" lazy style="width: 128px; height: 72px" />
             </template>
         </app-table-details>
-        <app-table-details :title="t('member.institution.open.details.subtitle2')" :data="data" :label-width="160" :cell-props="detailProps3" :column="2" v-else>
+        <app-table-details :title="t('member.institution.open.details.subtitle2')" :data="data" :label-width="160"
+            :cell-props="detailProps3" :column="2" v-else>
             <!-- 企业性质 -->
             <template #biznature="{ value }">
                 {{ biznatureEnum.getEnumTypeName(value) }}
@@ -44,7 +47,8 @@
                 <el-image :src="value" fit="cover" lazy style="width: 128px; height: 72px" />
             </template>
         </app-table-details>
-        <app-table-details :title="t('common.annex')" :data="data" :label-width="160" :cell-props="detailProps4" :column="2" />
+        <app-table-details :title="t('common.annex')" :data="data" :label-width="160" :cell-props="detailProps4"
+            :column="2" />
         <template #footer>
             <el-button @click="onCancel(false)">{{ t('operation.close') }}</el-button>
             <template v-if="data?.userstate === 2">
@@ -52,15 +56,15 @@
                 <el-button @click="openComponent('Agree')" type="primary">{{ t('operation.agree') }}</el-button>
             </template>
         </template>
-        <component ref="componentRef" v-bind="{ record }" :is="componentMap.get(componentId)"
-            @closed="closeComponent" v-if="componentId" />
+        <component ref="componentRef" v-bind="{ record }" :is="componentMap.get(componentId)" @closed="closeComponent"
+            v-if="componentId" />
     </app-drawer>
 </template>
 
 <script lang="ts" setup>
 import { shallowRef, PropType, defineAsyncComponent } from 'vue'
 import { ElMessage } from 'element-plus'
-import { formatDate } from '@/filters'
+import { formatDate, getFirstPathFullUrl } from '@/filters'
 import { useEnum } from '@/hooks/enum'
 import { useComponent } from '@/hooks/component'
 import { useRequest } from '@/hooks/request'
@@ -68,7 +72,6 @@ import { UserInfoType } from '@/constants/member'
 import { queryWskhUserinfoDetail } from '@/services/api/member'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import AppTableDetails from '@pc/components/base/table-details/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -105,15 +108,12 @@ const { data } = useRequest(queryWskhUserinfoDetail, {
     onSuccess: (res) => {
         const { cardfrontphotourl, cardbackphotourl, legalcardfrontphotourl, legalcardbackphotourl, attachment1, attachment2 } = res.data
         if (data.value) {
-            const baseUrl = service.getConfig('apiUrl')
-            const getUrl = (value: string) => value && new URL(value, baseUrl).href
-
-            data.value.cardfrontphotourl = getUrl(cardfrontphotourl)
-            data.value.cardbackphotourl = getUrl(cardbackphotourl)
-            data.value.legalcardfrontphotourl = getUrl(legalcardfrontphotourl)
-            data.value.legalcardbackphotourl = getUrl(legalcardbackphotourl)
-            data.value.attachment1 = getUrl(attachment1)
-            data.value.attachment2 = getUrl(attachment2)
+            data.value.cardfrontphotourl = getFirstPathFullUrl(cardfrontphotourl)
+            data.value.cardbackphotourl = getFirstPathFullUrl(cardbackphotourl)
+            data.value.legalcardfrontphotourl = getFirstPathFullUrl(legalcardfrontphotourl)
+            data.value.legalcardbackphotourl = getFirstPathFullUrl(legalcardbackphotourl)
+            data.value.attachment1 = getFirstPathFullUrl(attachment1)
+            data.value.attachment2 = getFirstPathFullUrl(attachment2)
         }
     },
     onError: (err) => {

+ 13 - 36
src/packages/pc/views/member/institution/open/components/edit/index.vue

@@ -112,6 +112,7 @@
 <script lang="ts" setup>
 import { ref, reactive, PropType, onMounted, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules, UploadUserFile } from 'element-plus'
+import { parseFilePaths, extractFilePaths } from '@/filters'
 import { decryptAES } from '@/services/crypto'
 import { useRequest } from '@/hooks/request'
 import { wskhUserinfoAdd, queryWskhUserinfoDetail } from '@/services/api/member'
@@ -121,7 +122,6 @@ import AppUpload from '@pc/components/base/upload/index.vue'
 import AppEnum from '@pc/components/modules/enum/index.vue'
 import AppRegion from '@pc/components/modules/region/index.vue'
 import AppSelectMember from '@pc/components/modules/select-member/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -162,32 +162,17 @@ const formData = ref<Partial<Member.MemberDetail>>({
     sex: Gender.Male
 })
 
-const getUploadFiles = (value?: string) => {
-    const paths = value ? value.split(',') : []
-    return paths.map((url) => {
-        const urlObj = new URL(url, service.getConfig('apiUrl'))
-        const name = urlObj.pathname.split('/').pop()
-        return {
-            name: name ?? urlObj.href,
-            url: urlObj.href,
-            response: {
-                data: [{ filePath: value }]
-            }
-        }
-    })
-}
-
 const { loading, run } = useRequest(queryWskhUserinfoDetail, {
     manual: true,
     onSuccess: ((res) => {
         res.data.cardnum = decryptAES(res.data.cardnum)
         formData.value = res.data
-        uploadFiles.cardfrontphotourl = getUploadFiles(res.data.cardfrontphotourl)
-        uploadFiles.cardbackphotourl = getUploadFiles(res.data.cardbackphotourl)
-        uploadFiles.legalcardfrontphotourl = getUploadFiles(res.data.legalcardfrontphotourl)
-        uploadFiles.legalcardbackphotourl = getUploadFiles(res.data.legalcardbackphotourl)
-        uploadFiles.attachment1 = getUploadFiles(res.data.attachment1)
-        uploadFiles.attachment2 = getUploadFiles(res.data.attachment2)
+        uploadFiles.cardfrontphotourl = parseFilePaths(res.data.cardfrontphotourl)
+        uploadFiles.cardbackphotourl = parseFilePaths(res.data.cardbackphotourl)
+        uploadFiles.legalcardfrontphotourl = parseFilePaths(res.data.legalcardfrontphotourl)
+        uploadFiles.legalcardbackphotourl = parseFilePaths(res.data.legalcardbackphotourl)
+        uploadFiles.attachment1 = parseFilePaths(res.data.attachment1)
+        uploadFiles.attachment2 = parseFilePaths(res.data.attachment2)
         referralRef.value.onReset(res.data.referral)
     }),
     onError: (err) => {
@@ -208,23 +193,15 @@ const onCancel = (isRefresh = false) => {
     refresh.value = isRefresh
 }
 
-// 更新上传文件到表单中
-const updateUploadFiles = (uploadFiles: UploadUserFile[]) => {
-    return uploadFiles.map((e) => {
-        const res = e.response as { data: { filePath: string }[] }
-        return res.data.map((e) => e.filePath)
-    }).join(',')
-}
-
 const onSubmit = () => {
     const rawData = { ...formData.value }
     rawData.userstate = 2
-    rawData.cardfrontphotourl = updateUploadFiles(uploadFiles.cardfrontphotourl)
-    rawData.cardbackphotourl = updateUploadFiles(uploadFiles.cardbackphotourl)
-    rawData.legalcardfrontphotourl = updateUploadFiles(uploadFiles.legalcardfrontphotourl)
-    rawData.legalcardbackphotourl = updateUploadFiles(uploadFiles.legalcardbackphotourl)
-    rawData.attachment1 = updateUploadFiles(uploadFiles.attachment1)
-    rawData.attachment2 = updateUploadFiles(uploadFiles.attachment2)
+    rawData.cardfrontphotourl = extractFilePaths(uploadFiles.cardfrontphotourl)
+    rawData.cardbackphotourl = extractFilePaths(uploadFiles.cardbackphotourl)
+    rawData.legalcardfrontphotourl = extractFilePaths(uploadFiles.legalcardfrontphotourl)
+    rawData.legalcardbackphotourl = extractFilePaths(uploadFiles.legalcardbackphotourl)
+    rawData.attachment1 = extractFilePaths(uploadFiles.attachment1)
+    rawData.attachment2 = extractFilePaths(uploadFiles.attachment2)
 
     formRef.value?.validate((valid) => {
         if (valid) {

+ 17 - 19
src/packages/pc/views/member/institution/user/components/details/index.vue

@@ -1,8 +1,9 @@
 <!-- 会员机构管理-机构管理-机构资料管理-详情 -->
 <template>
-    <app-drawer :title="t('member.institution.user.details.title')" width="900" v-model:show="show" :loading="loading" :refresh="refresh">
-        <app-table-details :title="t('member.institution.user.details.subtitle1')" :data="data?.rspResult" :label-width="160" :cell-props="detailProps1"
-            :column="2" />
+    <app-drawer :title="t('member.institution.user.details.title')" width="900" v-model:show="show" :loading="loading"
+        :refresh="refresh">
+        <app-table-details :title="t('member.institution.user.details.subtitle1')" :data="data?.rspResult"
+            :label-width="160" :cell-props="detailProps1" :column="2" />
         <app-table-details :title="t('member.institution.open.details.subtitle1')" :data="data?.userinfo"
             :label-width="160" :cell-props="detailProps2" :column="2">
             <!-- 证件照正面 -->
@@ -22,16 +23,17 @@
                 <el-image :src="value" fit="cover" lazy style="width: 128px; height: 72px" />
             </template>
         </app-table-details>
-        <app-table-details :title="t('member.institution.user.details.subtitle2')" :data="data?.users" :label-width="160" :cell-props="detailProps3"
-            :column="2" />
-        <app-table-details :title="t('member.institution.user.details.subtitle3')" :data="data?.userinfo" :label-width="160" :cell-props="detailProps4"
-            :column="2" v-if="data?.userinfo.bankid">
+        <app-table-details :title="t('member.institution.user.details.subtitle2')" :data="data?.users"
+            :label-width="160" :cell-props="detailProps3" :column="2" />
+        <app-table-details :title="t('member.institution.user.details.subtitle3')" :data="data?.userinfo"
+            :label-width="160" :cell-props="detailProps4" :column="2" v-if="data?.userinfo.bankid">
             <!-- 银行卡正面 -->
             <template #bankcardfrontphotourl="{ value }">
                 <el-image :src="value" fit="cover" lazy style="width: 128px; height: 72px" />
             </template>
         </app-table-details>
-        <app-table-details :title="t('member.institution.user.details.subtitle4')" :data="data?.userinfo" :label-width="160" :cell-props="detailProps5" :column="2"
+        <app-table-details :title="t('member.institution.user.details.subtitle4')" :data="data?.userinfo"
+            :label-width="160" :cell-props="detailProps5" :column="2"
             v-if="data?.userinfo.attachment1 || data?.userinfo.attachment2" />
         <template #footer>
             <el-button @click="onCancel(false)">{{ t('operation.close') }}</el-button>
@@ -42,7 +44,7 @@
 <script lang="ts" setup>
 import { shallowRef, PropType, computed } from 'vue'
 import { ElMessage } from 'element-plus'
-import { formatDate } from '@/filters'
+import { formatDate, getFirstPathFullUrl } from '@/filters'
 import { decryptAES } from '@/services/crypto'
 import { useEnum } from '@/hooks/enum'
 import { useRequest } from '@/hooks/request'
@@ -51,7 +53,6 @@ import { CellProp } from '@pc/components/base/table-details/types'
 import { queryOrganDetail } from '@/services/api/member'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import AppTableDetails from '@pc/components/base/table-details/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -86,15 +87,12 @@ const { data } = useRequest(queryOrganDetail, {
         const userInfo = data.value?.userinfo
 
         if (userInfo) {
-            const baseUrl = service.getConfig('apiUrl')
-            const getUrl = (value: string) => value && new URL(value, baseUrl).href
-
-            userInfo.cardfrontphotourl = getUrl(cardfrontphotourl)
-            userInfo.cardbackphotourl = getUrl(cardbackphotourl)
-            userInfo.legalcardfrontphotourl = getUrl(legalcardfrontphotourl)
-            userInfo.legalcardbackphotourl = getUrl(legalcardbackphotourl)
-            userInfo.attachment1 = getUrl(attachment1)
-            userInfo.attachment2 = getUrl(attachment2)
+            userInfo.cardfrontphotourl = getFirstPathFullUrl(cardfrontphotourl)
+            userInfo.cardbackphotourl = getFirstPathFullUrl(cardbackphotourl)
+            userInfo.legalcardfrontphotourl = getFirstPathFullUrl(legalcardfrontphotourl)
+            userInfo.legalcardbackphotourl = getFirstPathFullUrl(legalcardbackphotourl)
+            userInfo.attachment1 = getFirstPathFullUrl(attachment1)
+            userInfo.attachment2 = getFirstPathFullUrl(attachment2)
         }
     },
     onError: (err) => {

+ 46 - 56
src/packages/pc/views/member/institution/user/components/edit/index.vue

@@ -22,7 +22,9 @@
                 </el-form-item>
             </fieldset>
             <fieldset class="g-fieldset el-form--horizontal">
-                <legend class="g-fieldset__legend">{{ isPerson ? t('member.institution.user.edit.person') : t('member.institution.user.edit.enterprise') }}{{ t('member.institution.user.edit.legend') }}</legend>
+                <legend class="g-fieldset__legend">{{ isPerson ? t('member.institution.user.edit.person') :
+                    t('member.institution.user.edit.enterprise') }}{{ t('member.institution.user.edit.legend') }}
+                </legend>
                 <el-form-item label="名称" prop="customername">
                     <el-input v-model="formData.customername" maxlength="50" :placeholder="t('common.pleaseenter')" />
                 </el-form-item>
@@ -41,26 +43,31 @@
                 </el-form-item>
                 <el-form-item :label="t('member.institution.user.edit.cardfrontphotourl')" prop="cardfrontphotourl">
                     <app-upload v-model="uploadFiles.cardfrontphotourl" :file-types="['image']"
-                    :type-message="t('common.tips21')" />
+                        :type-message="t('common.tips21')" />
                 </el-form-item>
-                <el-form-item :label="t('member.institution.user.edit.cardbackphotourl')" prop="cardbackphotourl" v-if="isPerson">
+                <el-form-item :label="t('member.institution.user.edit.cardbackphotourl')" prop="cardbackphotourl"
+                    v-if="isPerson">
                     <app-upload v-model="uploadFiles.cardbackphotourl" :file-types="['image']"
-                    :type-message="t('common.tips21')" />
+                        :type-message="t('common.tips21')" />
                 </el-form-item>
                 <template v-if="!isPerson">
                     <el-form-item :label="t('member.institution.user.edit.legalpersonname')" prop="legalpersonname">
-                        <el-input v-model="formData.legalpersonname" maxlength="50" :placeholder="t('common.pleaseenter')" />
+                        <el-input v-model="formData.legalpersonname" maxlength="50"
+                            :placeholder="t('common.pleaseenter')" />
                     </el-form-item>
-                    <el-form-item :label="t('member.institution.user.edit.legalcardfrontphotourl')" prop="legalcardfrontphotourl">
+                    <el-form-item :label="t('member.institution.user.edit.legalcardfrontphotourl')"
+                        prop="legalcardfrontphotourl">
                         <app-upload v-model="uploadFiles.legalcardfrontphotourl" :file-types="['image']"
-                        :type-message="t('common.tips21')" />
+                            :type-message="t('common.tips21')" />
                     </el-form-item>
-                    <el-form-item :label="t('member.institution.user.edit.legalcardbackphotourl')" prop="legalcardbackphotourl">
+                    <el-form-item :label="t('member.institution.user.edit.legalcardbackphotourl')"
+                        prop="legalcardbackphotourl">
                         <app-upload v-model="uploadFiles.legalcardbackphotourl" :file-types="['image']"
-                        :type-message="t('common.tips21')" />
+                            :type-message="t('common.tips21')" />
                     </el-form-item>
                     <el-form-item :label="t('member.institution.user.edit.contactname')" prop="contactname">
-                        <el-input v-model="formData.contactname" maxlength="50" :placeholder="t('common.pleaseenter')" />
+                        <el-input v-model="formData.contactname" maxlength="50"
+                            :placeholder="t('common.pleaseenter')" />
                     </el-form-item>
                 </template>
                 <el-form-item :label="t('member.institution.user.edit.sex')" prop="sex">
@@ -71,16 +78,21 @@
                     </el-radio-group>
                 </el-form-item>
                 <el-form-item :label="t('member.institution.user.edit.mobile')" prop="mobile">
-                    <el-input type="number" v-model="formData.mobile" maxlength="50" :placeholder="t('common.pleaseenter')" />
+                    <el-input type="number" v-model="formData.mobile" maxlength="50"
+                        :placeholder="t('common.pleaseenter')" />
                 </el-form-item>
                 <el-form-item :label="t('member.institution.user.edit.telphone')" prop="telphone">
-                    <el-input type="number" v-model="formData.telphone" maxlength="50" :placeholder="t('common.pleaseenter')" />
+                    <el-input type="number" v-model="formData.telphone" maxlength="50"
+                        :placeholder="t('common.pleaseenter')" />
                 </el-form-item>
-                <el-form-item class="el-form-item--row" :label="t('member.institution.user.edit.provinceid')" prop="provinceid">
-                    <app-region class="el-form-item--col" v-model:country="formData.countryid" v-model:province="formData.provinceid"
-                        v-model:city="formData.cityid" v-model:district="formData.districtid" />
+                <el-form-item class="el-form-item--row" :label="t('member.institution.user.edit.provinceid')"
+                    prop="provinceid">
+                    <app-region class="el-form-item--col" v-model:country="formData.countryid"
+                        v-model:province="formData.provinceid" v-model:city="formData.cityid"
+                        v-model:district="formData.districtid" />
                 </el-form-item>
-                <el-form-item class="el-form-item--row" :label="t('member.institution.user.edit.address')" prop="address">
+                <el-form-item class="el-form-item--row" :label="t('member.institution.user.edit.address')"
+                    prop="address">
                     <el-input v-model="formData.address" maxlength="50" :placeholder="t('common.pleaseenter')" />
                 </el-form-item>
                 <el-form-item :label="t('member.institution.user.edit.postalcode')" prop="postalcode">
@@ -90,7 +102,8 @@
                     <el-input v-model="formData.email" maxlength="50" :placeholder="t('common.pleaseenter')" />
                 </el-form-item>
                 <el-form-item class="el-form-item--row" :label="t('member.institution.user.edit.remark')" prop="remark">
-                    <el-input type="textarea" v-model="formData.remark" maxlength="200" :rows="3" :placeholder="t('common.pleaseenter')" />
+                    <el-input type="textarea" v-model="formData.remark" maxlength="200" :rows="3"
+                        :placeholder="t('common.pleaseenter')" />
                 </el-form-item>
             </fieldset>
             <fieldset class="g-fieldset el-form--horizontal" v-if="data && data.rspResult.usertype !== 4">
@@ -98,7 +111,8 @@
                 <el-form-item :label="t('member.institution.user.edit.username1')">
                     {{ data.users.username }}
                 </el-form-item>
-                <el-form-item :label="t('member.institution.user.edit.userinfotype1')" prop="userinfotype" v-if="data.rspResult.usertype === 2">
+                <el-form-item :label="t('member.institution.user.edit.userinfotype1')" prop="userinfotype"
+                    v-if="data.rspResult.usertype === 2">
                     {{ data.rspResult.reckonaccountid }}
                 </el-form-item>
             </fieldset>
@@ -106,7 +120,7 @@
                 <legend class="g-fieldset__legend">{{ t('member.institution.user.edit.attachment') }}</legend>
                 <el-form-item :label="t('member.institution.user.edit.attachment1')" prop="attachment1">
                     <app-upload v-model="uploadFiles.attachment1" :file-types="['image', 'pdf']"
-                    :type-message="t('common.tips21')" />
+                        :type-message="t('common.tips21')" />
                 </el-form-item>
                 <el-form-item :label="t('member.institution.user.edit.attachment2')" prop="attachment2">
                     <app-upload v-model="uploadFiles.attachment2" :file-types="['image', 'pdf']"
@@ -124,7 +138,7 @@
 <script lang="ts" setup>
 import { ref, reactive, PropType, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules, UploadUserFile } from 'element-plus'
-import { handleNoneValue } from '@/filters'
+import { handleNoneValue, parseFilePaths, extractFilePaths } from '@/filters'
 import { useEnum } from '@/hooks/enum'
 import { decryptAES } from '@/services/crypto'
 import { useRequest } from '@/hooks/request'
@@ -135,7 +149,6 @@ import AppUpload from '@pc/components/base/upload/index.vue'
 import AppEnum from '@pc/components/modules/enum/index.vue'
 import AppRegion from '@pc/components/modules/region/index.vue'
 import AppSelectMember from '@pc/components/modules/select-member/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -176,21 +189,6 @@ const uploadFiles = reactive<{
 // 是否个人
 const isPerson = computed(() => formData.value.userinfotype === UserInfoType.Personal)
 
-const getUploadFiles = (value?: string) => {
-    const paths = value ? value.split(',') : []
-    return paths.map((url) => {
-        const urlObj = new URL(url, service.getConfig('apiUrl'))
-        const name = urlObj.pathname.split('/').pop()
-        return {
-            name: name ?? urlObj.href,
-            url: urlObj.href,
-            response: {
-                data: [{ filePath: value }]
-            }
-        }
-    })
-}
-
 const { data, loading } = useRequest(queryOrganDetail, {
     params: {
         areaId: props.record.userid
@@ -199,12 +197,12 @@ const { data, loading } = useRequest(queryOrganDetail, {
         const { rspResult, userinfo, users } = res.data
 
         if (userinfo) {
-            uploadFiles.cardfrontphotourl = getUploadFiles(userinfo.cardfrontphotourl)
-            uploadFiles.cardbackphotourl = getUploadFiles(userinfo.cardbackphotourl)
-            uploadFiles.legalcardfrontphotourl = getUploadFiles(userinfo.legalcardfrontphotourl)
-            uploadFiles.legalcardbackphotourl = getUploadFiles(userinfo.legalcardbackphotourl)
-            uploadFiles.attachment1 = getUploadFiles(userinfo.attachment1)
-            uploadFiles.attachment2 = getUploadFiles(userinfo.attachment2)
+            uploadFiles.cardfrontphotourl = parseFilePaths(userinfo.cardfrontphotourl)
+            uploadFiles.cardbackphotourl = parseFilePaths(userinfo.cardbackphotourl)
+            uploadFiles.legalcardfrontphotourl = parseFilePaths(userinfo.legalcardfrontphotourl)
+            uploadFiles.legalcardbackphotourl = parseFilePaths(userinfo.legalcardbackphotourl)
+            uploadFiles.attachment1 = parseFilePaths(userinfo.attachment1)
+            uploadFiles.attachment2 = parseFilePaths(userinfo.attachment2)
         }
 
         formData.value = {
@@ -266,22 +264,14 @@ const onCancel = (isRefresh = false) => {
     refresh.value = isRefresh
 }
 
-// 更新上传文件到表单中
-const updateUploadFiles = (uploadFiles: UploadUserFile[]) => {
-    return uploadFiles.map((e) => {
-        const res = e.response as { data: { filePath: string }[] }
-        return res.data.map((e) => e.filePath)
-    }).join(',')
-}
-
 const onSubmit = () => {
     const rawData = { ...formData.value }
-    rawData.cardfrontphotourl = updateUploadFiles(uploadFiles.cardfrontphotourl)
-    rawData.cardbackphotourl = updateUploadFiles(uploadFiles.cardbackphotourl)
-    rawData.legalcardfrontphotourl = updateUploadFiles(uploadFiles.legalcardfrontphotourl)
-    rawData.legalcardbackphotourl = updateUploadFiles(uploadFiles.legalcardbackphotourl)
-    rawData.attachment1 = updateUploadFiles(uploadFiles.attachment1)
-    rawData.attachment2 = updateUploadFiles(uploadFiles.attachment2)
+    rawData.cardfrontphotourl = extractFilePaths(uploadFiles.cardfrontphotourl)
+    rawData.cardbackphotourl = extractFilePaths(uploadFiles.cardbackphotourl)
+    rawData.legalcardfrontphotourl = extractFilePaths(uploadFiles.legalcardfrontphotourl)
+    rawData.legalcardbackphotourl = extractFilePaths(uploadFiles.legalcardbackphotourl)
+    rawData.attachment1 = extractFilePaths(uploadFiles.attachment1)
+    rawData.attachment2 = extractFilePaths(uploadFiles.attachment2)
 
     formRef.value?.validate((valid) => {
         if (valid) {

+ 3 - 4
src/packages/pc/views/member/institution/user/index.vue

@@ -6,7 +6,8 @@
                 <template #starttime="{ item }">
                     <el-form-item :label="item.label" prop="date">
                         <el-date-picker type="daterange" v-model="dateValue" value-format="YYYYMMDD"
-                            :start-placeholder="t('member.institution.user.startdate')" :end-placeholder="t('member.institution.user.enddate')" />
+                            :start-placeholder="t('member.institution.user.startdate')"
+                            :end-placeholder="t('member.institution.user.enddate')" />
                     </el-form-item>
                 </template>
             </app-filter>
@@ -121,7 +122,7 @@ const { filterOption, getQueryParams, resetFilters } = useDataFilter<Member.Orga
 
 // 处理操作按钮
 const handleOperateButtons = (row: Member.OrganDetailListRsp) => {
-    const buttons = ['member_institution_user_details']
+    const buttons = ['member_institution_user_details', 'member_institution_user_account', 'member_institution_user_login']
 
     if (row.accountstatus === 6) {
         buttons.push('member_institution_user_recover')
@@ -132,8 +133,6 @@ const handleOperateButtons = (row: Member.OrganDetailListRsp) => {
         }
     }
 
-    buttons.push('member_institution_user_account', 'member_institution_user_login')
-
     if (row.roleIds?.split(',').includes('6')) {
         buttons.push('member_institution_user_terminal')
     }

+ 13 - 16
src/packages/pc/views/member/subinstitution/manage/components/details/index.vue

@@ -192,7 +192,7 @@
 
 <script lang="ts" setup>
 import { ref, PropType, computed, defineAsyncComponent } from 'vue'
-import { handleNoneValue } from '@/filters'
+import { handleNoneValue, getFirstPathFullUrl } from '@/filters'
 import { decryptAES } from '@/services/crypto'
 import { useEnum } from '@/hooks/enum'
 import { useComponent } from '@/hooks/component'
@@ -202,7 +202,6 @@ import { organSonViewson } from '@/services/api/member'
 import { CellProp } from '@pc/components/base/table-details/types'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import AppTableDetails from '@pc/components/base/table-details/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -246,17 +245,15 @@ const { data } = useRequest(organSonViewson, {
     },
     onSuccess: (res) => {
         const { newResult, oldResult } = res.data
-        const baseUrl = service.getConfig('apiUrl')
-        const getUrl = (value: string) => value && new URL(value, baseUrl).href
 
         if (newResult?.userinfoDetailVo) {
             const detail = newResult.userinfoDetailVo
-            detail.cardFrontPhotoUrl = getUrl(detail.cardFrontPhotoUrl)
-            detail.cardBackPhotoUrl = getUrl(detail.cardBackPhotoUrl)
-            detail.halfBodyPhotoUrl = getUrl(detail.halfBodyPhotoUrl)
-            detail.legalCardFrontPhotoUrl = getUrl(detail.legalCardFrontPhotoUrl)
-            detail.legalCardBackPhotoUrl = getUrl(detail.legalCardBackPhotoUrl)
-            detail.otherUrl = getUrl(detail.otherUrl)
+            detail.cardFrontPhotoUrl = getFirstPathFullUrl(detail.cardFrontPhotoUrl)
+            detail.cardBackPhotoUrl = getFirstPathFullUrl(detail.cardBackPhotoUrl)
+            detail.halfBodyPhotoUrl = getFirstPathFullUrl(detail.halfBodyPhotoUrl)
+            detail.legalCardFrontPhotoUrl = getFirstPathFullUrl(detail.legalCardFrontPhotoUrl)
+            detail.legalCardBackPhotoUrl = getFirstPathFullUrl(detail.legalCardBackPhotoUrl)
+            detail.otherUrl = getFirstPathFullUrl(detail.otherUrl)
 
             detail.cardNum = decryptAES(detail.cardNum)
             detail.mobile = decryptAES(detail.mobile)
@@ -268,12 +265,12 @@ const { data } = useRequest(organSonViewson, {
         }
         if (oldResult?.userinfoDetailVo) {
             const detail = oldResult.userinfoDetailVo
-            detail.cardFrontPhotoUrl = getUrl(detail.cardFrontPhotoUrl)
-            detail.cardBackPhotoUrl = getUrl(detail.cardBackPhotoUrl)
-            detail.halfBodyPhotoUrl = getUrl(detail.halfBodyPhotoUrl)
-            detail.legalCardFrontPhotoUrl = getUrl(detail.legalCardFrontPhotoUrl)
-            detail.legalCardBackPhotoUrl = getUrl(detail.legalCardBackPhotoUrl)
-            detail.otherUrl = getUrl(detail.otherUrl)
+            detail.cardFrontPhotoUrl = getFirstPathFullUrl(detail.cardFrontPhotoUrl)
+            detail.cardBackPhotoUrl = getFirstPathFullUrl(detail.cardBackPhotoUrl)
+            detail.halfBodyPhotoUrl = getFirstPathFullUrl(detail.halfBodyPhotoUrl)
+            detail.legalCardFrontPhotoUrl = getFirstPathFullUrl(detail.legalCardFrontPhotoUrl)
+            detail.legalCardBackPhotoUrl = getFirstPathFullUrl(detail.legalCardBackPhotoUrl)
+            detail.otherUrl = getFirstPathFullUrl(detail.otherUrl)
 
             detail.cardNum = decryptAES(detail.cardNum)
             detail.mobile = decryptAES(detail.mobile)

+ 13 - 36
src/packages/pc/views/member/subinstitution/manage/components/edit/index.vue

@@ -173,6 +173,7 @@
 <script lang="ts" setup>
 import { ref, reactive, PropType, onMounted, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules, UploadUserFile } from 'element-plus'
+import { parseFilePaths, extractFilePaths } from '@/filters'
 import { decryptAES } from '@/services/crypto'
 import { useEnum } from '@/hooks/enum'
 import { useRequest } from '@/hooks/request'
@@ -184,7 +185,6 @@ import AppEnum from '@pc/components/modules/enum/index.vue'
 import AppRegion from '@pc/components/modules/region/index.vue'
 import AppSelectMember from '@pc/components/modules/select-member/index.vue'
 import AppSelectInstitution from '@pc/components/modules/select-institution/index.vue'
-import service from '@/services'
 import { i18n } from '@/stores'
 
 const props = defineProps({
@@ -234,21 +234,6 @@ const formData = ref<Partial<Member.OrganSonUpdateReq>>({
     usertype: 3
 })
 
-const getUploadFiles = (value?: string) => {
-    const paths = value ? value.split(',') : []
-    return paths.map((url) => {
-        const urlObj = new URL(url, service.getConfig('apiUrl'))
-        const name = urlObj.pathname.split('/').pop()
-        return {
-            name: name ?? urlObj.href,
-            url: urlObj.href,
-            response: {
-                data: [{ filePath: value }]
-            }
-        }
-    })
-}
-
 const { loading, run } = useRequest(organSonViewson, {
     manual: true,
     onSuccess: ((res) => {
@@ -285,12 +270,12 @@ const { loading, run } = useRequest(organSonViewson, {
             usertype: userAccountDetailVo.usertype,
             wechat: userinfoDetailVo.wechat
         }
-        uploadFiles.cardfrontphotourl = getUploadFiles(userinfoDetailVo.cardBackPhotoUrl)
-        uploadFiles.cardbackphotourl = getUploadFiles(userinfoDetailVo.cardFrontPhotoUrl)
-        uploadFiles.legalcardfrontphotourl = getUploadFiles(userinfoDetailVo.legalCardFrontPhotoUrl)
-        uploadFiles.legalcardbackphotourl = getUploadFiles(userinfoDetailVo.legalCardBackPhotoUrl)
-        uploadFiles.attachment1 = getUploadFiles(userinfoDetailVo.attachment1)
-        uploadFiles.attachment2 = getUploadFiles(userinfoDetailVo.attachment2)
+        uploadFiles.cardfrontphotourl = parseFilePaths(userinfoDetailVo.cardBackPhotoUrl)
+        uploadFiles.cardbackphotourl = parseFilePaths(userinfoDetailVo.cardFrontPhotoUrl)
+        uploadFiles.legalcardfrontphotourl = parseFilePaths(userinfoDetailVo.legalCardFrontPhotoUrl)
+        uploadFiles.legalcardbackphotourl = parseFilePaths(userinfoDetailVo.legalCardBackPhotoUrl)
+        uploadFiles.attachment1 = parseFilePaths(userinfoDetailVo.attachment1)
+        uploadFiles.attachment2 = parseFilePaths(userinfoDetailVo.attachment2)
 
         parentuseridRef.value?.onReset(userAccountDetailVo.parentuserid)
         refereeuseridRef.value.onReset(userAccountDetailVo.refereeuserid)
@@ -317,22 +302,14 @@ const onCancel = (isRefresh = false) => {
     refresh.value = isRefresh
 }
 
-// 更新上传文件到表单中
-const updateUploadFiles = (uploadFiles: UploadUserFile[]) => {
-    return uploadFiles.map((e) => {
-        const res = e.response as { data: { filePath: string }[] }
-        return res.data.map((e) => e.filePath)
-    }).join(',')
-}
-
 const onSubmit = (modifystatus: number, accountstatus?: number) => {
     const rawData = { ...formData.value }
-    rawData.cardfrontphotourl = updateUploadFiles(uploadFiles.cardfrontphotourl)
-    rawData.cardbackphotourl = updateUploadFiles(uploadFiles.cardbackphotourl)
-    rawData.legalcardfrontphotourl = updateUploadFiles(uploadFiles.legalcardfrontphotourl)
-    rawData.legalcardbackphotourl = updateUploadFiles(uploadFiles.legalcardbackphotourl)
-    rawData.attachment1 = updateUploadFiles(uploadFiles.attachment1)
-    rawData.attachment2 = updateUploadFiles(uploadFiles.attachment2)
+    rawData.cardfrontphotourl = extractFilePaths(uploadFiles.cardfrontphotourl)
+    rawData.cardbackphotourl = extractFilePaths(uploadFiles.cardbackphotourl)
+    rawData.legalcardfrontphotourl = extractFilePaths(uploadFiles.legalcardfrontphotourl)
+    rawData.legalcardbackphotourl = extractFilePaths(uploadFiles.legalcardbackphotourl)
+    rawData.attachment1 = extractFilePaths(uploadFiles.attachment1)
+    rawData.attachment2 = extractFilePaths(uploadFiles.attachment2)
 
     formRef.value?.validate((valid) => {
         if (valid) {

+ 82 - 0
src/packages/pc/views/notice/manage/components/audit/index.vue

@@ -0,0 +1,82 @@
+<!-- 通知公告-公告通知管理-审核 -->
+<template>
+    <Details ref="detailsRef" v-bind="{ record }" :loading="loading">
+        <el-button type="primary" @click="showDialog(1)">审核通过</el-button>
+        <el-button type="primary" @click="showDialog(0)">审核不通过</el-button>
+        <el-dialog v-model="dialogVisible" :title="formData.auditflag === 1 ? '提示' : ''" :width="480" append-to-body
+            align-center>
+            <span v-if="formData.auditflag === 1">确认提交审核吗?</span>
+            <el-form ref="formRef" class="el-form--vertical" label-width="100px" :model="formData" :rules="formRules"
+                :show-message="false" v-else>
+                <el-form-item label="不通过原因" prop="msg">
+                    <el-input type="textarea" v-model="formData.msg" maxlength="200" :rows="5" placeholder="请输入" />
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <el-button @click="dialogVisible = false">取消</el-button>
+                <el-button type="primary" @click="onSubmit">提交</el-button>
+            </template>
+        </el-dialog>
+    </Details>
+</template>
+
+<script lang="ts" setup>
+import { reactive, shallowRef, PropType } from 'vue'
+import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { auditinform } from '@/services/api/notice'
+import Details from '../details/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.QueryRsp>,
+        required: true
+    }
+})
+
+const formRef = shallowRef<FormInstance>()
+const detailsRef = shallowRef()
+const loading = shallowRef(false)
+const dialogVisible = shallowRef(false)
+
+const formData = reactive<Notice.AuditMsgReq>({
+    auditid: props.record.autoid,
+    auditflag: 0,
+})
+
+// 表单验证规则
+const formRules: FormRules = {
+    msg: [{ required: true }],
+}
+
+const showDialog = (auditflag: number) => {
+    formData.auditflag = auditflag
+    dialogVisible.value = true
+}
+
+const onSubmit = () => {
+    const run = () => {
+        loading.value = true
+        dialogVisible.value = false
+        auditinform({
+            data: formData
+        }).then(() => {
+            ElMessage.success('提交成功')
+            detailsRef.value?.close(true)
+        }).catch((err) => {
+            ElMessage.error('提交失败:' + err)
+            detailsRef.value?.close()
+        }).finally(() => {
+            loading.value = false
+        })
+    }
+    if (formRef.value) {
+        formRef.value.validate((valid) => {
+            if (valid) {
+                run()
+            }
+        })
+    } else {
+        run()
+    }
+}
+</script>

+ 52 - 0
src/packages/pc/views/notice/manage/components/delete/index.vue

@@ -0,0 +1,52 @@
+<!-- 通知公告-公告通知管理-删除 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">确定删除此条消息吗?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { noticeDelete } from '@/services/api/notice'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.QueryRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    noticeDelete({
+        data: {
+            auditid: props.record.autoid,
+        }
+    }).then(() => {
+        ElMessage.success(t('common.tips5'))
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error(t('common.tips6') + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 22 - 8
src/packages/pc/views/notice/manage/components/details/index.vue

@@ -1,13 +1,16 @@
 <!-- 通知公告-公告通知管理-详情 -->
 <template>
-    <app-drawer :title="t('investor.manage.cancelapply.details.title')" width="900" v-model:show="show">
-        <app-table-details :data="data" :label-width="120" :cell-props="detailProps" :column="2">
+    <app-drawer :title="t('investor.manage.cancelapply.details.title')" width="900" v-model:show="show"
+        :refresh="refresh">
+        <app-table-details title="信息" :data="data" :label-width="120" :cell-props="detailProps1" :column="2">
             <template #content="{ value }">
                 <div v-html="value"></div>
             </template>
         </app-table-details>
+        <app-table-details title="审核" :data="data" :label-width="120" :cell-props="detailProps2" :column="2" />
         <template #footer>
-            <el-button @click="onCancel">{{ t('operation.close') }}</el-button>
+            <el-button @click="close(false)">{{ t('operation.close') }}</el-button>
+            <slot></slot>
         </template>
     </app-drawer>
 </template>
@@ -33,6 +36,7 @@ const props = defineProps({
 
 const { global: { t } } = i18n
 const show = shallowRef(true)
+const refresh = shallowRef(false)
 
 const msgtypeEnum = useEnum('msgtype') // 消息类型
 const sendtypeEnum = useEnum('sendtype') // 发布类型
@@ -46,21 +50,31 @@ const { data } = useRequest(noticeMsgDetail, {
     }
 })
 
-const detailProps = computed<CellProp[]>(() => [
-    { prop: 'title', label: '标题' },
+const detailProps1 = computed<CellProp[]>(() => [
     { prop: 'msgtype', label: '消息类型', formatValue: (val) => msgtypeEnum.getEnumTypeName(val) },
     { prop: 'sendtype', label: '推送方式', formatValue: (val) => sendtypeEnum.getEnumTypeName(val) },
+    { prop: 'membername', label: '接收交易商', show: props.record.sendtype === 3 },
+    { prop: 'membername', label: '接收会员', show: props.record.sendtype === 2 || props.record.sendtype === 4 },
     { prop: 'scheduletime', label: '生效时间', formatValue: (val) => formatDate(val) },
     { prop: 'endtime', label: '结束时间', formatValue: (val) => formatDate(val) },
     { prop: 'creatorName', label: '录入人' },
     { prop: 'createtime', label: '录入时间', formatValue: (val) => formatDate(val) },
-    { prop: 'content', label: '内容', entireRow: true },
+    { prop: 'title', label: '标题', entireRow: true },
+    { prop: 'content', label: '内容', entireRow: true }
+])
+
+const detailProps2 = computed<CellProp[]>(() => [
     { prop: 'auditName', label: '审核人' },
-    { prop: 'audittime', label: '审核时间' },
+    { prop: 'audittime', label: '审核时间', formatValue: (val) => formatDate(val) },
     { prop: 'auditremark', label: '备注' },
 ])
 
-const onCancel = () => {
+const close = (isRefresh = false) => {
     show.value = false
+    refresh.value = isRefresh
 }
+
+defineExpose({
+    close
+})
 </script>

+ 58 - 29
src/packages/pc/views/notice/manage/components/edit/index.vue

@@ -8,31 +8,42 @@
                 <el-input v-model="formData.title" :placeholder="t('common.pleaseenter')" />
             </el-form-item>
             <el-form-item label="消息类型" prop="msgtype">
-                <el-select v-model="formData.msgtype">
+                <el-select v-model="formData.msgtype" :disabled="!!formData.autoid">
                     <el-option v-for="item in msgtypeEnum.getEnumOptions()" :key="item.value" :label="item.label"
                         :value="item.value" />
                 </el-select>
             </el-form-item>
             <el-form-item label="发布类型" prop="sendtype">
-                <el-select v-model="formData.sendtype">
+                <el-select v-model="formData.sendtype" :disabled="!!formData.autoid">
                     <el-option v-for="item in sendtypeEnum.getEnumOptions()" :key="item.value" :label="item.label"
                         :value="item.value" />
                 </el-select>
             </el-form-item>
-            <el-form-item label="接收会员" prop="memberidlist" v-if="formData.sendtype === 2 || formData.sendtype === 4">
-                <el-input :value="selectedValues.map((e) => e.accountname)" placeholder="请选择" readonly>
-                    <template #append>
-                        <el-button @click="showSelectMember = true">选择</el-button>
-                    </template>
-                </el-input>
-            </el-form-item>
-            <el-form-item label="接收交易商" prop="invertorID" v-if="formData.sendtype === 3">
-                <app-select-investor v-model="formData.invertorID" />
-            </el-form-item>
+            <template v-if="formData.autoid">
+                <el-form-item label="接收会员" v-if="formData.sendtype === 2 || formData.sendtype === 4">
+                    <el-input :value="data?.membername" disabled />
+                </el-form-item>
+                <el-form-item label="接收交易商" v-if="formData.sendtype === 3">
+                    <el-input :value="data?.membername" disabled />
+                </el-form-item>
+            </template>
+            <template v-else>
+                <el-form-item label="接收会员" prop="memberidlist"
+                    v-if="formData.sendtype === 2 || formData.sendtype === 4">
+                    <el-input :value="selectedValues.map((e) => e.accountname)" placeholder="请选择" readonly>
+                        <template #append>
+                            <el-button @click="showSelectMember = true">选择</el-button>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-form-item label="接收交易商" prop="invertorID" v-if="formData.sendtype === 3">
+                    <app-select-investor v-model="formData.invertorID" />
+                </el-form-item>
+            </template>
             <el-form-item label="开始结束" prop="date">
                 <el-date-picker v-model="dateValue" type="datetimerange"
-                    :disabled-date="(date: Date) => date.getTime() < Date.now() - 8.64e7"
-                    start-placeholder="生效时间" end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" />
+                    :disabled-date="(date: Date) => date.getTime() < Date.now() - 8.64e7" start-placeholder="生效时间"
+                    end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" />
             </el-form-item>
             <el-form-item label="内容" prop="content">
                 <app-editor v-model="formData.content" />
@@ -49,9 +60,10 @@
 <script lang="ts" setup>
 import { ref, PropType, onMounted } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { formatDate } from '@/filters'
 import { useRequest } from '@/hooks/request'
 import { useEnum } from '@/hooks/enum'
-import { noticemsgadd, noticeMsgDetail } from '@/services/api/notice'
+import { noticemsgadd, noticemsgedit, noticeMsgDetail } from '@/services/api/notice'
 import { i18n } from '@/stores'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import AppSelectInvestor from '@pc/components/modules/select-investor/index.vue'
@@ -77,14 +89,18 @@ const dateValue = ref<string[]>([])
 
 const formData = ref<Partial<Notice.NoticeMsgAddReq>>({})
 
-const { loading, run } = useRequest(noticeMsgDetail, {
+const { data, loading, run } = useRequest(noticeMsgDetail, {
     manual: true,
     onSuccess: ((res) => {
-        const { title, content } = res.data
+        const { autoid, title, content, endtime, msgtype, scheduletime, sendtype } = res.data
         formData.value = {
-            title,
-            content
+            autoid,
+            content,
+            msgtype,
+            sendtype,
+            title
         }
+        dateValue.value = [formatDate(scheduletime), formatDate(endtime)]
     }),
     onError: (err) => {
         ElMessage.error(err)
@@ -123,16 +139,29 @@ const onSubmit = () => {
     formRef.value?.validate((valid) => {
         if (valid) {
             loading.value = true
-            noticemsgadd({
-                data: rawData
-            }).then(() => {
-                ElMessage.success(t('common.tips3'))
-                onCancel(true)
-            }).catch((err) => {
-                ElMessage.error(t('common.tips4') + err)
-            }).finally(() => {
-                loading.value = false
-            })
+            if (rawData.autoid) {
+                noticemsgedit({
+                    data: rawData
+                }).then(() => {
+                    ElMessage.success(t('common.tips3'))
+                    onCancel(true)
+                }).catch((err) => {
+                    ElMessage.error(t('common.tips4') + err)
+                }).finally(() => {
+                    loading.value = false
+                })
+            } else {
+                noticemsgadd({
+                    data: rawData
+                }).then(() => {
+                    ElMessage.success(t('common.tips3'))
+                    onCancel(true)
+                }).catch((err) => {
+                    ElMessage.error(t('common.tips4') + err)
+                }).finally(() => {
+                    loading.value = false
+                })
+            }
         }
     })
 }

+ 56 - 0
src/packages/pc/views/notice/manage/components/forced/index.vue

@@ -0,0 +1,56 @@
+<!-- 通知公告-公告通知管理-弹出 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">
+            <span v-if="record.isforcedisplay">是否取消强制弹出此公告消息?</span>
+            <span v-else>是否强制弹出此公告消息?</span>
+        </div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { updateforcedisplay } from '@/services/api/notice'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.QueryRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    updateforcedisplay({
+        data: {
+            auditid: props.record.autoid,
+            isforcedisplay: props.record.isforcedisplay ? 0 : 1,
+        }
+    }).then(() => {
+        ElMessage.success('操作成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('操作失败:' + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 33 - 7
src/packages/pc/views/notice/manage/index.vue

@@ -17,8 +17,7 @@
             </template>
             <!-- 操作 -->
             <template #operate="{ row }">
-                <app-operation size="small"
-                    :data-list="getActionButtons(['notice_manage_details', 'notice_manage_delete', 'notice_manage_force'])"
+                <app-operation size="small" :data-list="handleOperateButtons(row)"
                     @click="(code: string) => openComponent(code, row)" circle />
             </template>
             <template #footer>
@@ -41,6 +40,7 @@ import { useOperation } from '@/hooks/operation'
 import { useEnum } from '@/hooks/enum'
 import { query } from '@/services/api/notice'
 import { i18n } from '@/stores'
+import moment from 'moment'
 import AppTable from '@pc/components/base/table/index.vue'
 import AppPagination from '@pc/components/base/pagination/index.vue'
 import AppOperation from '@pc/components/base/operation/index.vue'
@@ -48,6 +48,7 @@ import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
 import AppSelectInvestor from '@pc/components/modules/select-investor/index.vue'
 
 const { global: { t } } = i18n
+const flagEnum = useEnum('flag')
 const msgtypeEnum = useEnum('msgtype') // 消息类型
 const sendtypeEnum = useEnum('sendtype') // 发布类型
 const sendstatusEnum = useEnum('sendstatus') // 推送状态
@@ -74,7 +75,7 @@ const tableColumns = shallowRef<Model.TableColumn[]>([
     { field: 'scheduletime', label: 'notice.manage.scheduletime', formatValue: (val) => formatDate(val) },
     { field: 'endtime', label: 'notice.manage.endtime', formatValue: (val) => formatDate(val) },
     { field: 'recipient', label: 'notice.manage.recipient' },
-    { field: 'operate', label: 'common.operate', fixed: 'right' }
+    { field: 'operate', label: 'common.operate', fixed: 'right', width: 200 }
 ])
 
 const { queryParams, filterOption, getQueryParams, resetFilters } = useDataFilter<Notice.QueryReq>({
@@ -104,10 +105,7 @@ const { queryParams, filterOption, getQueryParams, resetFilters } = useDataFilte
         {
             field: 'isforcedisplay',
             label: t('notice.manage.isforcedisplay'),
-            options: () => [
-                { label: '是', value: 1 },
-                { label: '否', value: 0 }
-            ]
+            options: () => flagEnum.getEnumOptions()
         },
     ],
     buttons: [
@@ -116,6 +114,34 @@ const { queryParams, filterOption, getQueryParams, resetFilters } = useDataFilte
     ]
 })
 
+// 处理操作按钮
+const handleOperateButtons = (row: Notice.QueryRsp) => {
+    const buttons = ['notice_manage_details', 'notice_manage_delete']
+
+    if (row.sentstatus === 0) {
+        buttons.push('notice_manage_audit')
+        const startDate = moment(row.scheduletime)
+        if (moment().isBefore(startDate)) {
+            buttons.push('notice_manage_modify')
+        }
+    }
+
+    if (row.msgtype === 1 && row.sentstatus === 1) {
+        const endDate = moment(row.endtime)
+        if (moment().isBefore(endDate)) {
+            buttons.push('notice_manage_finish')
+        }
+    }
+
+    if (row.isforcedisplay) {
+        buttons.push('notice_manage_unforced')
+    } else {
+        buttons.push('notice_manage_forced')
+    }
+
+    return getActionButtons(buttons)
+}
+
 const onSearch = () => {
     const qs = getQueryParams()
     run(qs)

+ 55 - 0
src/packages/pc/views/notice/newscolumn/components/delete/index.vue

@@ -0,0 +1,55 @@
+<!-- 通知公告-资讯栏目-删除 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">
+            <span>确认删除栏目?</span>
+            <span>栏目下明细将同步删除且不可恢复!</span>
+        </div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { columndelete } from '@/services/api/notice'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.ColumnQueryRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    columndelete({
+        data: {
+            id: props.record.id,
+        }
+    }).then(() => {
+        ElMessage.success(t('common.tips5'))
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error(t('common.tips6') + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 58 - 0
src/packages/pc/views/notice/newscolumn/components/details/index.vue

@@ -0,0 +1,58 @@
+<!-- 通知公告-资讯栏目-详情 -->
+<template>
+    <app-drawer :title="t('investor.manage.cancelapply.details.title')" width="480" v-model:show="show">
+        <app-table-details :data="data" :label-width="120" :cell-props="detailProps" :column="1" />
+        <template #footer>
+            <el-button @click="close">{{ t('operation.close') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType, computed } from 'vue'
+import { ElMessage } from 'element-plus'
+import { formatDate } from '@/filters'
+import { useEnum } from '@/hooks/enum'
+import { useRequest } from '@/hooks/request'
+import { columnDetail } from '@/services/api/notice'
+import { CellProp } from '@pc/components/base/table-details/types'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.ColumnQueryRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+
+const flagEnum = useEnum('flag')
+const columntypeEnum = useEnum('columntype') // 栏目类型
+
+const { data } = useRequest(columnDetail, {
+    params: {
+        id: props.record.id,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const detailProps = computed<CellProp[]>(() => [
+    { prop: 'columntype', label: '栏目类型', formatValue: (val) => columntypeEnum.getEnumTypeName(val) },
+    { prop: 'columnname', label: '栏目名称' },
+    { prop: 'isshow', label: '是否展示', formatValue: (val) => flagEnum.getEnumTypeName(val) },
+    { prop: 'creatoruser', label: '创建人' },
+    { prop: 'creaedate', label: '创建时间', formatValue: (val) => formatDate(val) },
+    { prop: 'modifieruser', label: '操作人' },
+    { prop: 'updatedate', label: '修改时间', formatValue: (val) => formatDate(val) }
+])
+
+const close = () => {
+    show.value = false
+}
+</script>

+ 115 - 0
src/packages/pc/views/notice/newscolumn/components/edit/index.vue

@@ -0,0 +1,115 @@
+<!-- 通知公告-资讯栏目-编辑 -->
+<template>
+    <app-drawer :title="t('investor.user.open.edit.title')" width="480" v-model:show="show" :refresh="refresh"
+        :loading="loading">
+        <el-form ref="formRef" class="el-form--vertical" label-width="100px" :model="formData" :rules="formRules"
+            :show-message="false">
+            <el-form-item label="栏目类型" prop="columntype">
+                <el-select v-model="formData.columntype">
+                    <el-option v-for="item in columntypeEnum.getEnumOptions()" :key="item.value" :label="item.label"
+                        :value="item.value" />
+                </el-select>
+            </el-form-item>
+            <el-form-item label="栏目名称" prop="columnname">
+                <el-input v-model="formData.columnname" :placeholder="t('common.pleaseenter')" />
+            </el-form-item>
+            <el-form-item label="排序" prop="sort">
+                <el-input-number v-model="formData.sort" :placeholder="t('common.pleaseenter')" />
+            </el-form-item>
+            <el-form-item label="是否展示" prop="isshow">
+                <el-radio-group v-model="formData.isshow">
+                    <el-radio v-for="item in flagEnum.getEnumOptions()" :key="item.value" :value="item.value"
+                        :label="item.label" />
+                </el-radio-group>
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.close') }}</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType, onMounted } from 'vue'
+import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { useRequest } from '@/hooks/request'
+import { useEnum } from '@/hooks/enum'
+import { dealcolumn, columnDetail } from '@/services/api/notice'
+import { i18n } from '@/stores'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.ColumnQueryRsp>
+    }
+})
+
+const flagEnum = useEnum('flag')
+const columntypeEnum = useEnum('columntype') // 栏目类型
+
+const { global: { t } } = i18n
+const formRef = ref<FormInstance>()
+const show = ref(true)
+const refresh = ref(false)
+
+const formData = ref<Partial<Notice.DealColumnReq>>({
+    isshow: 1,
+    sort: 1
+})
+
+const { loading, run } = useRequest(columnDetail, {
+    manual: true,
+    onSuccess: ((res) => {
+        const { id, columnname, columntype, isshow, sort } = res.data
+        formData.value = {
+            id,
+            columnname,
+            columntype,
+            isshow,
+            sort
+        }
+    }),
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+// 表单验证规则
+const formRules: FormRules = {
+    columntype: [{ required: true }],
+    columnname: [{ required: true }],
+    sort: [{ required: true }],
+    isshow: [{ required: true }],
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            loading.value = true
+            dealcolumn({
+                data: formData.value
+            }).then(() => {
+                ElMessage.success(t('common.tips3'))
+                onCancel(true)
+            }).catch((err) => {
+                ElMessage.error(t('common.tips4') + err)
+            }).finally(() => {
+                loading.value = false
+            })
+        }
+    })
+}
+
+onMounted(() => {
+    const id = props.record?.id
+    if (id) {
+        run({ id })
+    }
+})
+</script>

+ 97 - 1
src/packages/pc/views/notice/newscolumn/index.vue

@@ -1,7 +1,103 @@
 <!-- 通知公告-资讯栏目 -->
 <template>
-    <app-view></app-view>
+    <app-view>
+        <template #header>
+            <app-filter :option="filterOption">
+                <template #userid="{ item }">
+                    <el-form-item :label="item.label">
+                        <app-select-investor v-model="item.value" />
+                    </el-form-item>
+                </template>
+            </app-filter>
+        </template>
+        <app-table :data="dataList" :columns="tableColumns" :loading="loading">
+            <template #headerLeft>
+                <app-operation :data-list="getActionButtons(['notice_newscolumn_add'])"
+                    @click="(code: string) => openComponent(code)" />
+            </template>
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <app-operation size="small"
+                    :data-list="getActionButtons(['notice_newscolumn_details', 'notice_newscolumn_modify', 'notice_newscolumn_delete'])"
+                    @click="(code: string) => openComponent(code, row)" circle />
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="onSearch" />
+            </template>
+        </app-table>
+        <component :is="componentMap.get(componentId)" v-bind="{ record, queryParams }" @closed="closeComponent"
+            v-if="componentId" />
+    </app-view>
 </template>
 
 <script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { ElMessage } from 'element-plus'
+import { formatDate } from '@/filters'
+import { useDataFilter } from '@/hooks/datatable-v2'
+import { useRequest } from '@/hooks/request'
+import { useOperation } from '@/hooks/operation'
+import { useEnum } from '@/hooks/enum'
+import { columnquery } from '@/services/api/notice'
+import { i18n } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppOperation from '@pc/components/base/operation/index.vue'
+import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
+
+const { global: { t } } = i18n
+const flagEnum = useEnum('flag')
+const columntypeEnum = useEnum('columntype') // 栏目类型
+
+const { componentMap, componentId, record, openComponent, closeComponent, getActionButtons } = useOperation<Notice.ColumnQueryRsp>({
+    onClose: () => onSearch()
+})
+
+const { dataList, total, pageSize, pageIndex, loading, run } = useRequest(columnquery, {
+    params: {
+        pageNum: 1,
+        pageSize: 20
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { field: 'columnname', label: '栏目名称' },
+    { field: 'sort', label: '排序' },
+    { field: 'isshow', label: '是否展示', formatValue: (val) => flagEnum.getEnumTypeName(val) },
+    { field: 'creatoruser', label: '创建人' },
+    { field: 'creaedate', label: '创建时间', formatValue: (val) => formatDate(val) },
+    { field: 'operate', label: 'common.operate', fixed: 'right' }
+])
+
+const { queryParams, filterOption, getQueryParams, resetFilters } = useDataFilter<Notice.ColumnQueryReq>({
+    filters: [
+        {
+            field: 'columntype',
+            label: '栏目类型',
+            options: () => columntypeEnum.getEnumOptions()
+        },
+        {
+            field: 'columnname',
+            label: '栏目名称'
+        },
+        {
+            field: 'isshow',
+            label: '是否展示',
+            options: () => flagEnum.getEnumOptions()
+        },
+    ],
+    buttons: [
+        { label: t('operation.search'), className: 'el-button--primary', onClick: () => onSearch() },
+        { label: t('operation.reset'), className: 'el-button--primary', validateEvent: false, onClick: () => resetFilters() }
+    ]
+})
+
+const onSearch = () => {
+    const qs = getQueryParams()
+    run(qs)
+}
 </script>

+ 52 - 0
src/packages/pc/views/notice/newssource/components/delete/index.vue

@@ -0,0 +1,52 @@
+<!-- 通知公告-资讯来源-删除 -->
+<template>
+    <app-drawer :title="t('common.alert')" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div class="g-text-message">您确定要删除该数据吗?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.cancel') }}</el-button>
+            <el-button type="primary" @click="onSubmit">{{ t('operation.confirm') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { columnsourcedelete } from '@/services/api/notice'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.ColumnSourceQueryRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    loading.value = true
+    columnsourcedelete({
+        data: {
+            memberid: props.record.memberid,
+        }
+    }).then(() => {
+        ElMessage.success(t('common.tips5'))
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error(t('common.tips6') + err)
+        onCancel()
+    }).finally(() => {
+        loading.value = false
+    })
+}
+</script>

+ 56 - 0
src/packages/pc/views/notice/newssource/components/details/index.vue

@@ -0,0 +1,56 @@
+<!-- 通知公告-资讯来源-详情 -->
+<template>
+    <app-drawer :title="t('investor.manage.cancelapply.details.title')" width="480" v-model:show="show">
+        <app-table-details :data="data" :label-width="120" :cell-props="detailProps" :column="1">
+            <!-- 来源LOGO -->
+            <template #imageurl="{ value }">
+                <el-image style="width: 200px; height: 100px" :src="getFirstPathFullUrl(value)" fit="contain" />
+            </template>
+        </app-table-details>
+        <template #footer>
+            <el-button @click="close">{{ t('operation.close') }}</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType, computed } from 'vue'
+import { ElMessage } from 'element-plus'
+import { formatDate, getFirstPathFullUrl } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { columnsourceDetail } from '@/services/api/notice'
+import { CellProp } from '@pc/components/base/table-details/types'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+import { i18n } from '@/stores'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.ColumnSourceQueryRsp>,
+        required: true
+    }
+})
+
+const { global: { t } } = i18n
+const show = shallowRef(true)
+
+const { data } = useRequest(columnsourceDetail, {
+    params: {
+        memberid: props.record.memberid,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const detailProps = computed<CellProp[]>(() => [
+    { prop: 'membername', label: '来源名称' },
+    { prop: 'membertags', label: '来源网址' },
+    { prop: 'imageurl', label: '来源LOGO' },
+    { prop: 'updatetime', label: '更新时间', formatValue: (val) => formatDate(val) }
+])
+
+const close = () => {
+    show.value = false
+}
+</script>

+ 104 - 0
src/packages/pc/views/notice/newssource/components/edit/index.vue

@@ -0,0 +1,104 @@
+<!-- 通知公告-资讯来源-编辑 -->
+<template>
+    <app-drawer :title="t('investor.user.open.edit.title')" width="480" v-model:show="show" :refresh="refresh"
+        :loading="loading">
+        <el-form ref="formRef" class="el-form--vertical" label-width="100px" :model="formData" :rules="formRules"
+            :show-message="false">
+            <el-form-item label="来源名称" prop="membername">
+                <el-input v-model="formData.membername" :placeholder="t('common.pleaseenter')" />
+            </el-form-item>
+            <el-form-item label="来源网址" prop="membertags">
+                <el-input v-model="formData.membertags" :placeholder="t('common.pleaseenter')" />
+            </el-form-item>
+            <el-form-item label="来源LOGO" prop="imageurl">
+                <app-upload v-model="uploadFiles" :file-types="['image']" />
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)">{{ t('operation.close') }}</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType, onMounted } from 'vue'
+import { ElMessage, FormInstance, FormRules, UploadUserFile } from 'element-plus'
+import { parseFilePaths, extractFilePaths } from '@/filters'
+import { useRequest } from '@/hooks/request'
+import { dealcolumnsource, columnsourceDetail } from '@/services/api/notice'
+import { i18n } from '@/stores'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppUpload from '@pc/components/base/upload/index.vue'
+
+const props = defineProps({
+    record: {
+        type: Object as PropType<Notice.ColumnSourceQueryRsp>
+    }
+})
+
+const { global: { t } } = i18n
+const formRef = ref<FormInstance>()
+const show = ref(true)
+const refresh = ref(false)
+const uploadFiles = ref<UploadUserFile[]>([])
+
+const formData = ref<Notice.DealColumnSourceReq>({
+    membername: ''
+})
+
+const { loading, run } = useRequest(columnsourceDetail, {
+    manual: true,
+    onSuccess: ((res) => {
+        const { memberid, imageurl, membername, membertags } = res.data
+        formData.value = {
+            memberid,
+            imageurl,
+            membername,
+            membertags
+        }
+        uploadFiles.value = parseFilePaths(imageurl)
+    }),
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+// 表单验证规则
+const formRules: FormRules = {
+    membername: [{ required: true }],
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    const rawData = { ...formData.value }
+    rawData.imageurl = extractFilePaths(uploadFiles.value)
+
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            loading.value = true
+            dealcolumnsource({
+                data: rawData
+            }).then(() => {
+                ElMessage.success(t('common.tips3'))
+                onCancel(true)
+            }).catch((err) => {
+                ElMessage.error(t('common.tips4') + err)
+            }).finally(() => {
+                loading.value = false
+            })
+        }
+    })
+}
+
+onMounted(() => {
+    const memberid = props.record?.memberid
+    if (memberid) {
+        run({ memberid })
+    }
+})
+</script>

+ 86 - 1
src/packages/pc/views/notice/newssource/index.vue

@@ -1,7 +1,92 @@
 <!-- 通知公告-资讯来源 -->
 <template>
-    <app-view></app-view>
+    <app-view>
+        <template #header>
+            <app-filter :option="filterOption">
+                <template #userid="{ item }">
+                    <el-form-item :label="item.label">
+                        <app-select-investor v-model="item.value" />
+                    </el-form-item>
+                </template>
+            </app-filter>
+        </template>
+        <app-table :data="dataList" :columns="tableColumns" :loading="loading">
+            <template #headerLeft>
+                <app-operation :data-list="getActionButtons(['notice_newssource_add'])"
+                    @click="(code: string) => openComponent(code)" />
+            </template>
+            <!-- 来源LOGO -->
+            <template #imageurl="{ value }">
+                <el-image style="width: 100px; height: 50px" :src="getFirstPathFullUrl(value)" fit="contain" />
+            </template>
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <app-operation size="small"
+                    :data-list="getActionButtons(['notice_newssource_details', 'notice_newssource_modify', 'notice_newssource_delete'])"
+                    @click="(code: string) => openComponent(code, row)" circle />
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="onSearch" />
+            </template>
+        </app-table>
+        <component :is="componentMap.get(componentId)" v-bind="{ record, queryParams }" @closed="closeComponent"
+            v-if="componentId" />
+    </app-view>
 </template>
 
 <script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { ElMessage } from 'element-plus'
+import { getFirstPathFullUrl } from '@/filters'
+import { useDataFilter } from '@/hooks/datatable-v2'
+import { useRequest } from '@/hooks/request'
+import { useOperation } from '@/hooks/operation'
+import { columnsourcequery } from '@/services/api/notice'
+import { i18n } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppOperation from '@pc/components/base/operation/index.vue'
+import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
+
+const { global: { t } } = i18n
+
+const { componentMap, componentId, record, openComponent, closeComponent, getActionButtons } = useOperation<Notice.ColumnSourceQueryRsp>({
+    onClose: () => onSearch()
+})
+
+const { dataList, total, pageSize, pageIndex, loading, run } = useRequest(columnsourcequery, {
+    params: {
+        pageNum: 1,
+        pageSize: 20
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { field: 'imageurl', label: '来源LOGO' },
+    { field: 'membername', label: '来源名称' },
+    { field: 'membertags', label: '来源网址' },
+    { field: 'operate', label: 'common.operate', fixed: 'right' }
+])
+
+const { queryParams, filterOption, getQueryParams, resetFilters } = useDataFilter<Notice.ColumnSourceQueryReq>({
+    filters: [
+        {
+            field: 'smembername',
+            label: '来源名称'
+        },
+    ],
+    buttons: [
+        { label: t('operation.search'), className: 'el-button--primary', onClick: () => onSearch() },
+        { label: t('operation.reset'), className: 'el-button--primary', validateEvent: false, onClick: () => resetFilters() }
+    ]
+})
+
+const onSearch = () => {
+    const qs = getQueryParams()
+    run(qs)
+}
 </script>

+ 7 - 4
src/packages/pc/views/query/internal/offlinedelivery/components/details/index.vue

@@ -1,7 +1,7 @@
 <!-- 查询管理-内部订单查询-线下交收单查询-详情 -->
 <template>
     <app-drawer :title="t('query.internal.offlinedelivery.details.title')" width="960" v-model:show="show">
-        <app-table-details :data="data" :label-width="160" :cell-props="detailProps1" :column="2" />
+        <app-table-details :data="data" :label-width="160" :cell-props="detailProps" :column="2" />
         <template #footer>
             <el-button @click="onCancel">{{ t('operation.close') }}</el-button>
         </template>
@@ -9,7 +9,7 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, PropType } from 'vue'
+import { shallowRef, PropType, computed } from 'vue'
 import { ElMessage } from 'element-plus'
 import { formatDate } from '@/filters'
 import { getBuyOrSellName } from '@/constants/order'
@@ -39,7 +39,7 @@ const { data } = useRequest(queryOfflineDetail, {
     }
 })
 
-const detailProps1: CellProp[] = [
+const detailProps = computed<CellProp[]>(() => [
     { prop: 'deliveryorderid', label: 'query.internal.offlinedelivery.details.deliveryorderid' },
     { prop: 'username', label: 'query.internal.offlinedelivery.details.username' },
     { prop: 'goodsdisplay', label: 'query.internal.offlinedelivery.details.goodsdisplay' },
@@ -55,8 +55,11 @@ const detailProps1: CellProp[] = [
     { prop: 'orderstatusdisplay', label: 'query.internal.offlinedelivery.details.orderstatusdisplay' },
     { prop: 'remark', label: 'query.internal.offlinedelivery.details.remark' },
     { prop: 'deliverycharge', label: 'query.internal.offlinedelivery.details.deliverycharge' },
+    { prop: 'totalpricemove', label: '总升贴水', show: !!data.value?.totalpricemove },
+    { prop: 'totalshippingfee', label: '总运费', show: !!data.value?.totalshippingfee },
+    { prop: 'totalotherfee', label: '总其它费用', show: !!data.value?.totalotherfee },
     { prop: 'closetime', label: 'query.internal.offlinedelivery.details.closetime', formatValue: (val) => formatDate(val) },
-]
+])
 
 const onCancel = () => {
     show.value = false

+ 5 - 2
src/packages/pc/views/query/internal/offlinedelivery/index.vue

@@ -5,7 +5,8 @@
             <app-filter :option="filterOption">
                 <template #startdate="{ item }">
                     <el-form-item :label="item.label" prop="cycletime">
-                        <el-date-picker v-model="item.value" value-format="YYYYMMDD" :placeholder="t('common.pleasechoice')" />
+                        <el-date-picker v-model="item.value" value-format="YYYYMMDD"
+                            :placeholder="t('common.pleasechoice')" />
                     </el-form-item>
                 </template>
             </app-filter>
@@ -35,6 +36,7 @@ import { shallowRef } from 'vue'
 import { ElMessage } from 'element-plus'
 import { BuyOrSell, getBuyOrSellList } from '@/constants/order'
 import { useDataFilter } from '@/hooks/datatable-v2'
+import { useEnum } from '@/hooks/enum'
 import { useRequest } from '@/hooks/request'
 import { useOperation } from '@/hooks/operation'
 import { queryOffline } from '@/services/api/order'
@@ -45,6 +47,7 @@ import AppOperation from '@pc/components/base/operation/index.vue'
 import AppFilter from '@pc/components/base/table-filter-v2/index.vue'
 
 const { global: { t } } = i18n
+const deliveryOrderStatusEnum = useEnum('deliveryOrderStatus') // 单据状态
 
 const { componentMap, componentId, record, openComponent, closeComponent, getActionButtons } = useOperation<Model.OfflineRsp>({
     onClose: () => onSearch()
@@ -80,7 +83,7 @@ const { queryParams, filterOption, getQueryParams, resetFilters } = useDataFilte
         {
             field: 'deliveryorderstatus',
             label: t('query.internal.offlinedelivery.deliveryorderstatus'),
-            options: () => []
+            options: () => deliveryOrderStatusEnum.getEnumOptions()
         },
         {
             field: 'deliverygoodsname',

+ 87 - 3
src/services/api/notice/index.ts

@@ -2,6 +2,20 @@ import httpClient from '@/services/http'
 import { CommonFetchOptions } from '@/services/http/types'
 
 /**
+ * 通知公告-->发布通知公告
+ */
+export function noticemsgadd(options: CommonFetchOptions<{ request: Partial<Notice.NoticeMsgAddReq>; }>) {
+    return httpClient.commonRequest('/notice/noticemsgadd', 'post', options)
+}
+
+/**
+ * 通知公告-->发布通知公告-->修改
+ */
+export function noticemsgedit(options: CommonFetchOptions<{ request: Partial<Notice.NoticeMsgAddReq>; }>) {
+    return httpClient.commonRequest('/notice/noticemsgedit', 'post', options)
+}
+
+/**
  * 通知公告-->公告通知管理-->获取列表
  */
 export function query(options: CommonFetchOptions<{ request: Notice.QueryReq; response: Notice.QueryRsp[]; }>) {
@@ -16,10 +30,80 @@ export function noticeMsgDetail(options: CommonFetchOptions<{ request: Notice.No
 }
 
 /**
- * 通知公告-->发布通知公告
+ * 通知公告-->公告通知管理-->审核
  */
-export function noticemsgadd(options: CommonFetchOptions<{ request: Partial<Notice.NoticeMsgAddReq>; }>) {
-    return httpClient.commonRequest('/notice/noticemsgadd', 'post', options)
+export function auditinform(options: CommonFetchOptions<{ request: Notice.AuditMsgReq; }>) {
+    return httpClient.commonRequest('/notice/auditMsg', 'get', options)
+}
+
+/**
+ * 通知公告-->公告通知管理-->强制弹出/取消强制弹出
+ */
+export function updateforcedisplay(options: CommonFetchOptions<{ request: Notice.UpdateForceDisplayReq; }>) {
+    return httpClient.commonRequest('/notice/updateforcedisplay', 'get', options)
+}
+
+/**
+ * 通知公告-->公告通知管理-->删除
+ */
+export function noticeDelete(options: CommonFetchOptions<{ request: Notice.NoticeDeleteReq; }>) {
+    return httpClient.commonRequest('/notice/delete', 'get', options)
+}
+
+/**
+ * 通知公告-->资讯栏目-->获取列表
+ */
+export function columnquery(options: CommonFetchOptions<{ request: Notice.ColumnQueryReq; response: Notice.ColumnQueryRsp[]; }>) {
+    return httpClient.commonRequest('/notice/columnquery', 'get', options)
+}
+
+/**
+ * 通知公告-->资讯栏目-->详情
+ */
+export function columnDetail(options: CommonFetchOptions<{ request: Notice.ColumnDetailReq; response: Notice.ColumnDetailRsp; }>) {
+    return httpClient.commonRequest('/notice/columnDetail', 'get', options)
+}
+
+/**
+ * 通知公告-->资讯栏目-->新增/修改
+ */
+export function dealcolumn(options: CommonFetchOptions<{ request: Partial<Notice.DealColumnReq>; }>) {
+    return httpClient.commonRequest('/notice/dealcolumn', 'post', options)
+}
+
+/**
+ * 通知公告-->资讯栏目-->删除
+ */
+export function columndelete(options: CommonFetchOptions<{ request: Notice.ColumnDeleteReq; }>) {
+    return httpClient.commonRequest('/notice/columndelete', 'get', options)
+}
+
+/**
+ * 通知公告-->资讯来源-->新增/修改
+ */
+export function dealcolumnsource(options: CommonFetchOptions<{ request: Notice.DealColumnSourceReq; }>) {
+    return httpClient.commonRequest('/notice/dealcolumnsource', 'post', options)
+}
+
+/**
+ * 通知公告-->资讯来源-->获取列表
+ */
+export function columnsourcequery(options: CommonFetchOptions<{ request: Notice.ColumnSourceQueryReq; response: Notice.ColumnSourceQueryRsp[]; }>) {
+    return httpClient.commonRequest('/notice/columnsourcequery', 'get', options)
+}
+
+/**
+ * 通知公告-->资讯来源-->详情
+ */
+export function columnsourceDetail(options: CommonFetchOptions<{ request: Notice.ColumnSourceDetailReq; response: Notice.ColumnSourceDetailRsp; }>) {
+    return httpClient.commonRequest('/notice/columnsourceDetail', 'get', options)
+}
+
+/**
+ * 通知公告-->资讯来源-->删除
+ */
+export function columnsourcedelete(options: CommonFetchOptions<{ request: Notice.ColumnSourceDeleteReq; }>) {
+    return httpClient.commonRequest('/notice/columnsourcedelete', 'get', options)
 }
 
 /**

+ 122 - 3
src/types/model/notice.d.ts

@@ -1,5 +1,5 @@
 declare namespace Notice {
-    /** 通知公告-->资讯管理-->获取列表 请求 */
+    /** 通知公告-->公告通知管理-->获取列表 请求 */
     interface QueryReq {
         content?: string; // 消息内容
         isforcedisplay?: number; // 是否强制弹出
@@ -12,7 +12,7 @@ declare namespace Notice {
         userid?: number; // 接收交易商
     }
 
-    /** 通知公告-->资讯管理-->获取列表 响应 */
+    /** 通知公告-->公告通知管理-->获取列表 响应 */
     interface QueryRsp {
         autoid: number;
         endtime: string; // 结束时间
@@ -57,6 +57,7 @@ declare namespace Notice {
 
     /** 通知公告-->发布通知公告 请求 */
     interface NoticeMsgAddReq {
+        autoid?: number;
         content: string; // 内容
         endtime: string; // 结束时间
         invertorID: string; // 接收交易商
@@ -67,6 +68,124 @@ declare namespace Notice {
         title: string; // 标题
     }
 
+    /** 通知公告-->公告通知管理-->审核 请求 */
+    interface AuditMsgReq {
+        auditflag: number;
+        auditid: number;
+        msg?: string;
+    }
+
+    /** 通知公告-->公告通知管理-->强制弹出/取消强制弹出 请求 */
+    interface UpdateForceDisplayReq {
+        auditid: number;
+        isforcedisplay: number;
+    }
+
+    /** 通知公告-->公告通知管理-->删除 请求 */
+    interface NoticeDeleteReq {
+        auditid: number;
+    }
+
+    /** 通知公告-->资讯栏目-->获取列表 请求 */
+    interface ColumnQueryReq {
+        columnname?: string; // 栏目名称
+        columntype?: number; // 栏目类型
+        isshow?: number; // 是否展示
+        pageNum: number;
+        pageSize: number;
+    }
+
+    /** 通知公告-->资讯栏目-->获取列表 响应 */
+    interface ColumnQueryRsp {
+        columnname: string; // 栏目名称
+        creaedate: string; // 创建时间
+        creatorid: number;
+        creatoruser: string; // 创建人
+        id: number;
+        isshow: number; // 是否展示
+        sort: number; // 排序
+    }
+
+    /** 通知公告-->资讯栏目-->详情 请求 */
+    interface ColumnDetailReq {
+        id: number;
+    }
+
+    /** 通知公告-->资讯栏目-->详情 响应 */
+    interface ColumnDetailRsp {
+        columnname: string; // 栏目名称
+        columntype: number; // 栏目类型 - 1:行情资讯 10:会员服务 30:关于我们 100:核心企业栏目-百色
+        creaedate: string; // 创建时间
+        creatorid: number; // 创建人
+        creatoruser: string;
+        id: number; // ID(SEQ_SITE_COLUMNCONFIG)
+        isshow: number; // 是否展示 - 0:不展示 1:展示
+        modifierid: number; // 操作人
+        modifieruser: string;
+        sort: number; // 排序
+        updatedate: string; // 修改时间
+    }
+
+    /** 通知公告-->资讯栏目-->新增/修改 请求 */
+    interface DealColumnReq {
+        columnname: string; // 栏目名称
+        columntype: number; // 栏目类型
+        id?: number;
+        isshow: number; // 是否展示
+        sort: number; // 排序
+    }
+
+    /** 通知公告-->资讯栏目-->删除 请求 */
+    interface ColumnDeleteReq {
+        id: number;
+    }
+
+    /** 通知公告-->资讯来源-->新增/修改 请求 */
+    interface DealColumnSourceReq {
+        imageurl?: string; // 来源LOGO
+        memberid?: number;
+        membername: string; // 来源名称
+        membertags?: string; // 来源网址
+    }
+
+    /** 通知公告-->资讯来源-->获取列表 请求 */
+    interface ColumnSourceQueryReq {
+        smembername?: string;
+        pageNum: number;
+        pageSize: number;
+    }
+
+    /** 通知公告-->资讯来源-->获取列表 响应 */
+    interface ColumnSourceQueryRsp {
+        imageurl: string; // 来源LOGO
+        memberid: number;
+        membername: string; // 来源名称
+        membertags: string; // 来源网址
+    }
+
+    /** 通知公告-->资讯来源-->详情 请求 */
+    interface ColumnSourceDetailReq {
+        memberid: number;
+    }
+
+    /** 通知公告-->资讯来源-->详情 响应 */
+    interface ColumnSourceDetailRsp {
+        contactname: string; // 联系人
+        contactphone: string; // 电话
+        contactwx: string; // 微信号
+        imageurl: string; // 图片地址来源LOGO
+        memberid: number; // 会员ID(SEQ_GZ_MEMBERINFO)
+        membername: string; // 会员名称来源名称
+        membertags: string; // 标签(逗号分隔)来源网址
+        orderindex: number; // 显示顺序
+        updatetime: string; // 更新时间
+    }
+
+    /** 通知公告-->资讯来源-->删除 请求 */
+    interface ColumnSourceDeleteReq {
+        memberid: number;
+    }
+
     /** 通知公告-->资讯管理-->获取列表 请求 */
     interface InformManqueryReq {
         columnid?: number; // 类型
@@ -78,7 +197,7 @@ declare namespace Notice {
         userid?: number;
     }
 
-    /** 通知公告-->公告通知管理-->获取列表 响应 */
+    /** 通知公告-->资讯管理-->获取列表 响应 */
     interface InformManqueryRsp {
         author: string; // 作者
         columnname: string; // 资讯类型

+ 3 - 0
src/types/model/order.d.ts

@@ -1517,6 +1517,9 @@ declare namespace Model {
         remark: string; // 备注
         reqtime: string; // 申请时间
         sucdeliveryqty: number; // 实际交收数量
+        totalotherfee: number; // 总其它费用
+        totalpricemove: number; // 总升贴水
+        totalshippingfee: number; // 总运费
         username: string; // 申请人
     }