Commit f801d1bc138d1b3eb41ece9decdd00563f319247

Authored by xp.Huang
2 parents 55a68bee 89ba4c36

Merge branch 'perf/three-editor/10-23/2024' into 'main_dev'

feat(src/packages): 3d编辑器 新增批量操作(删除,发布,取消发布)

See merge request yunteng/thingskit-view!297
@@ -112,7 +112,7 @@ export const uploadFile = async (file: FormData, mode: ErrorMessageMode = 'modal @@ -112,7 +112,7 @@ export const uploadFile = async (file: FormData, mode: ErrorMessageMode = 'modal
112 export function threeJsDeleteApi(ids: string[], mode: ErrorMessageMode = 'modal') { 112 export function threeJsDeleteApi(ids: string[], mode: ErrorMessageMode = 'modal') {
113 return defHttp.delete( 113 return defHttp.delete(
114 { 114 {
115 - url: Api.THREE_JS_MODEL +'?ids=' + ids, 115 + url: Api.THREE_JS_MODEL + '?ids=' + ids
116 }, 116 },
117 { 117 {
118 errorMessageMode: mode 118 errorMessageMode: mode
@@ -145,7 +145,7 @@ export const putThreeJsModelRelease = (params: { id: string | number; state: num @@ -145,7 +145,7 @@ export const putThreeJsModelRelease = (params: { id: string | number; state: num
145 */ 145 */
146 export const updateThreeJsModel = (params: { id: string; name: string }) => { 146 export const updateThreeJsModel = (params: { id: string; name: string }) => {
147 return defHttp.put({ 147 return defHttp.put({
148 - url: Api.THREE_JS_MODEL +'/' + params['id'] + '/' + params['name'], 148 + url: Api.THREE_JS_MODEL + '/' + params['id'] + '/' + params['name'],
149 params 149 params
150 }) 150 })
151 } 151 }
@@ -155,7 +155,7 @@ export const updateThreeJsModel = (params: { id: string; name: string }) => { @@ -155,7 +155,7 @@ export const updateThreeJsModel = (params: { id: string; name: string }) => {
155 */ 155 */
156 export function saveOrUpdateThreeJsModel(params: Recordable) { 156 export function saveOrUpdateThreeJsModel(params: Recordable) {
157 return defHttp.post({ 157 return defHttp.post({
158 - url: Api.THREE_JS_MODEL +'/' + params['id'], 158 + url: Api.THREE_JS_MODEL + '/' + params['id'],
159 data: params['data'] 159 data: params['data']
160 }) 160 })
161 } 161 }
@@ -165,7 +165,16 @@ export function saveOrUpdateThreeJsModel(params: Recordable) { @@ -165,7 +165,16 @@ export function saveOrUpdateThreeJsModel(params: Recordable) {
165 */ 165 */
166 export function getThreeJsModel(id: string) { 166 export function getThreeJsModel(id: string) {
167 return defHttp.get({ 167 return defHttp.get({
168 - url: Api.THREE_JS_MODEL +'/' + id, 168 + url: Api.THREE_JS_MODEL + '/' + id
169 }) 169 })
170 } 170 }
171 171
  172 +/**
  173 + * @description: 3D模型 批量发布/取消发布 api
  174 + */
  175 +export function putReleaseThreeJsModel(state: number, ids: string[]) {
  176 + return defHttp.put({
  177 + url: Api.THREE_JS_MODEL + '/publish/' + state,
  178 + data: ids
  179 + })
  180 +}
1 <template> 1 <template>
2 <div v-if="cardData" class="go-items-list-card"> 2 <div v-if="cardData" class="go-items-list-card">
3 - <n-card :hoverable="false" size="small"> 3 + <n-card hoverable size="small">
  4 + <template v-if="operationKey">
  5 + <n-checkbox v-model:checked="cardData.checkedValue"> </n-checkbox>
  6 + </template>
4 <div class="list-content"> 7 <div class="list-content">
5 <div class="list-content-img"> 8 <div class="list-content-img">
6 <n-image 9 <n-image
@@ -98,7 +101,8 @@ const { EllipsisHorizontalCircleSharpIcon, TrashIcon, HammerIcon, SendIcon } = i @@ -98,7 +101,8 @@ const { EllipsisHorizontalCircleSharpIcon, TrashIcon, HammerIcon, SendIcon } = i
98 const emit = defineEmits(['delete', 'resize', 'edit', 'release', 'inputUpdateCard']) 101 const emit = defineEmits(['delete', 'resize', 'edit', 'release', 'inputUpdateCard'])
99 102
100 const props = defineProps({ 103 const props = defineProps({
101 - cardData: Object as PropType<ChartType> 104 + cardData: Object as PropType<ChartType>,
  105 + operationKey: String,
102 }) 106 })
103 107
104 // 处理url获取 108 // 处理url获取
@@ -197,9 +201,9 @@ $contentHeight: 180px; @@ -197,9 +201,9 @@ $contentHeight: 180px;
197 border-radius: $--border-radius-base; 201 border-radius: $--border-radius-base;
198 border: 1px solid rgba(0, 0, 0, 0); 202 border: 1px solid rgba(0, 0, 0, 0);
199 @extend .go-transition; 203 @extend .go-transition;
200 - &:hover {  
201 - @include hover-border-color('hover-border-color');  
202 - } 204 + // &:hover {
  205 + // @include hover-border-color('hover-border-color');
  206 + // }
203 .list-content { 207 .list-content {
204 cursor: pointer; 208 cursor: pointer;
205 border-radius: $--border-radius-base; 209 border-radius: $--border-radius-base;
@@ -44,7 +44,8 @@ export const useDataListInit = (formValue: { name: string; state: string | null @@ -44,7 +44,8 @@ export const useDataListInit = (formValue: { name: string; state: string | null
44 pagination.count = total 44 pagination.count = total
45 list.value = items.map(item => ({ 45 list.value = items.map(item => ({
46 ...item, 46 ...item,
47 - threeModelFilePath: `${threeFilePath}${VITE_GLOB_API_URL}${VITE_GLOB_API_URL_PREFIX}/3d_component/json/${item.id}/scene.json` 47 + threeModelFilePath: `${threeFilePath}${VITE_GLOB_API_URL}${VITE_GLOB_API_URL_PREFIX}/3d_component/json/${item.id}/scene.json`,
  48 + checkedValue: false
48 })) 49 }))
49 setTimeout(() => { 50 setTimeout(() => {
50 loading.value = false 51 loading.value = false
@@ -40,7 +40,18 @@ @@ -40,7 +40,18 @@
40 <div style="display: flex; flex-direction: row-reverse"> 40 <div style="display: flex; flex-direction: row-reverse">
41 <n-space> 41 <n-space>
42 <n-button type="primary" @click="handleOpenThreeEditor"> 新增 </n-button> 42 <n-button type="primary" @click="handleOpenThreeEditor"> 新增 </n-button>
43 - <!-- <n-button disabled> 批量操作 </n-button> --> 43 + <n-button v-if="list.length" @click="handleSelectAll" type="info">
  44 + {{ selectAllTextFlag ? '全选' : '反选' }}
  45 + </n-button>
  46 + <n-dropdown
  47 + v-if="list.length"
  48 + :disabled="isBulkOperationFlag"
  49 + trigger="hover"
  50 + :options="operationOptions"
  51 + @select="handleOperationSelect"
  52 + >
  53 + <n-button :disabled="isBulkOperationFlag"> 批量操作 </n-button>
  54 + </n-dropdown>
44 </n-space> 55 </n-space>
45 </div> 56 </div>
46 <n-grid style="margin-top: 16px" :x-gap="20" :y-gap="20" cols="2 s:2 m:3 l:4 xl:4 xxl:4" responsive="screen"> 57 <n-grid style="margin-top: 16px" :x-gap="20" :y-gap="20" cols="2 s:2 m:3 l:4 xl:4 xxl:4" responsive="screen">
@@ -48,6 +59,7 @@ @@ -48,6 +59,7 @@
48 <div style="display: none">{{ index }}</div> 59 <div style="display: none">{{ index }}</div>
49 <project-items-card 60 <project-items-card
50 :cardData="item" 61 :cardData="item"
  62 + :operationKey="operationKey"
51 @resize="resizeHandle" 63 @resize="resizeHandle"
52 @delete="deleteHandle(item)" 64 @delete="deleteHandle(item)"
53 @release="releaseHandle(item)" 65 @release="releaseHandle(item)"
@@ -89,6 +101,10 @@ import { ref } from 'vue' @@ -89,6 +101,10 @@ import { ref } from 'vue'
89 import type { FormInst } from 'naive-ui' 101 import type { FormInst } from 'naive-ui'
90 import { icon } from '@/plugins' 102 import { icon } from '@/plugins'
91 import { getUUID } from '@/utils/utils' 103 import { getUUID } from '@/utils/utils'
  104 +import { threeJsDeleteApi, putReleaseThreeJsModel } from '@/api/external/contentSave/content'
  105 +import { ChartType } from '../..'
  106 +import { DialogEnum } from '@/enums/pluginEnum'
  107 +import { goDialog } from '@/utils'
92 108
93 const { SearchIcon, ReloadSearch } = icon.ionicons5 109 const { SearchIcon, ReloadSearch } = icon.ionicons5
94 110
@@ -114,6 +130,88 @@ const statusOptions = ref([ @@ -114,6 +130,88 @@ const statusOptions = ref([
114 } 130 }
115 ]) 131 ])
116 132
  133 +const operationKey = ref('')
  134 +
  135 +const operationOptions = [
  136 + {
  137 + label: '批量删除',
  138 + key: 'Bulk delete'
  139 + },
  140 + {
  141 + label: '批量发布',
  142 + key: 'Bulk release'
  143 + },
  144 + {
  145 + label: '批量取消发布',
  146 + key: 'Bulk un release'
  147 + }
  148 +]
  149 +
  150 +const resetSelect = (list: ChartType[], flag: boolean) => {
  151 + list.forEach(item => {
  152 + item.checkedValue = flag
  153 + })
  154 +}
  155 +
  156 +const releaseGoDialog = (message: string, state: number, messageText: string) => {
  157 + goDialog({
  158 + type: DialogEnum.DELETE,
  159 + promise: true,
  160 + message,
  161 + // eslint-disable-next-line @typescript-eslint/no-empty-function
  162 + onPositiveCallback: () => {},
  163 + promiseResCallback: async () => {
  164 + console.log(list.value)
  165 + // eslint-disable-next-line no-case-declarations
  166 + const bulkDeleteIds = list.value
  167 + ?.filter((item: ChartType) => item.checkedValue)
  168 + ?.map((item: ChartType) => item.id)
  169 + await putReleaseThreeJsModel(state, bulkDeleteIds as unknown as string[])
  170 + window['$message'].success(window['$t'](messageText))
  171 + handleSearchClick()
  172 + isBulkOperationFlag.value = true
  173 + selectAllTextFlag.value = false
  174 + operationKey.value = ''
  175 + resetSelect(list.value, false)
  176 + }
  177 + })
  178 +}
  179 +
  180 +const handleOperationSelect = async (key: string) => {
  181 + operationKey.value = key
  182 + switch (key) {
  183 + case 'Bulk delete':
  184 + goDialog({
  185 + type: DialogEnum.DELETE,
  186 + promise: true,
  187 + message: '是否批量删除所选数据?',
  188 + // eslint-disable-next-line @typescript-eslint/no-empty-function
  189 + onPositiveCallback: () => {},
  190 + promiseResCallback: async () => {
  191 + console.log(list.value)
  192 + // eslint-disable-next-line no-case-declarations
  193 + const bulkDeleteIds = list.value
  194 + ?.filter((item: ChartType) => item.checkedValue)
  195 + ?.map((item: ChartType) => item.id)
  196 + await threeJsDeleteApi([bulkDeleteIds] as unknown as string[])
  197 + window['$message'].success(window['$t']('common.deleteSuccessText'))
  198 + handleSearchClick()
  199 + isBulkOperationFlag.value = true
  200 + selectAllTextFlag.value = false
  201 + operationKey.value = ''
  202 + resetSelect(list.value, false)
  203 + }
  204 + })
  205 + break
  206 + case 'Bulk release':
  207 + releaseGoDialog('是否批量发布所选数据?', 1, 'common.releaseSuccessText')
  208 + break
  209 + case 'Bulk un release':
  210 + releaseGoDialog('是否批量取消发布所选数据?', 0, 'common.cancelReleaseSuccessText')
  211 + break
  212 + }
  213 +}
  214 +
117 const { 215 const {
118 loading, 216 loading,
119 pagination, 217 pagination,
@@ -126,6 +224,23 @@ const { @@ -126,6 +224,23 @@ const {
126 handleSearchClick 224 handleSearchClick
127 } = useDataListInit(formValue.value) 225 } = useDataListInit(formValue.value)
128 226
  227 +const isBulkOperationFlag = ref(true)
  228 +
  229 +const selectAllTextFlag = ref(true)
  230 +
  231 +const handleSelectAll = () => {
  232 + selectAllTextFlag.value = !selectAllTextFlag.value
  233 + if (!selectAllTextFlag.value) {
  234 + resetSelect(list.value, true)
  235 + isBulkOperationFlag.value = false
  236 + operationKey.value = 'Bulk delete'
  237 + } else {
  238 + resetSelect(list.value, false)
  239 + isBulkOperationFlag.value = true
  240 + operationKey.value = ''
  241 + }
  242 +}
  243 +
129 const handleResetClick = () => { 244 const handleResetClick = () => {
130 formValue.value.name = '' 245 formValue.value.name = ''
131 formValue.value.state = null 246 formValue.value.state = null
@@ -151,7 +266,7 @@ $contentHeight: 250px; @@ -151,7 +266,7 @@ $contentHeight: 250px;
151 } 266 }
152 .list-pagination { 267 .list-pagination {
153 position: fixed; 268 position: fixed;
154 - bottom: 30px; 269 + bottom: 10px;
155 right: 30px; 270 right: 30px;
156 } 271 }
157 } 272 }
@@ -9,6 +9,7 @@ export type ChartType = { @@ -9,6 +9,7 @@ export type ChartType = {
9 name?: string 9 name?: string
10 threeModelFilePath?: string 10 threeModelFilePath?: string
11 imageUrl?: string | undefined 11 imageUrl?: string | undefined
  12 + checkedValue?: boolean
12 } 13 }
13 14
14 export type ChartList = ChartType[] 15 export type ChartList = ChartType[]