Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into feature/bpm

This commit is contained in:
YunaiV 2025-02-13 19:01:02 +08:00
commit 45ac20e5c3
54 changed files with 7554 additions and 6099 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "yudao-ui-admin-vue3", "name": "yudao-ui-admin-vue3",
"version": "2.4.0-snapshot", "version": "2.4.1-snapshot",
"description": "基于vue3、vite4、element-plus、typesScript", "description": "基于vue3、vite4、element-plus、typesScript",
"author": "xingyu", "author": "xingyu",
"private": false, "private": false,

12874
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -83,5 +83,5 @@ export const reqCheck = (data: any) => {
// 通过短信重置密码 // 通过短信重置密码
export const smsResetPassword = (data: any) => { export const smsResetPassword = (data: any) => {
return request.post({ url: '/system/auth/sms-reset-password', data }) return request.post({ url: '/system/auth/reset-password', data })
} }

View File

@ -51,7 +51,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ComponentStyle, usePropertyForm } from '@/components/DiyEditor/util' import { ComponentStyle } from '@/components/DiyEditor/util'
import { useVModel } from '@vueuse/core'
/** /**
* 组件容器属性目前右边部分 * 组件容器属性目前右边部分
@ -61,7 +62,7 @@ defineOptions({ name: 'ComponentContainer' })
const props = defineProps<{ modelValue: ComponentStyle }>() const props = defineProps<{ modelValue: ComponentStyle }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
const treeData = [ const treeData = [
{ {

View File

@ -93,14 +93,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { CarouselProperty } from './config' import { CarouselProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'CarouselProperty' }) defineOptions({ name: 'CarouselProperty' })
const props = defineProps<{ modelValue: CarouselProperty }>() const props = defineProps<{ modelValue: CarouselProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -68,15 +68,20 @@
</el-form> </el-form>
</ComponentContainerProperty> </ComponentContainerProperty>
<!-- 优惠券选择 --> <!-- 优惠券选择 -->
<CouponSelect ref="couponSelectDialog" v-model:multiple-selection="couponList" /> <CouponSelect
ref="couponSelectDialog"
v-model:multiple-selection="couponList"
:take-type="CouponTemplateTakeTypeEnum.USER.type"
@change="handleCouponSelect"
/>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { CouponCardProperty } from './config' import { CouponCardProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import * as CouponTemplateApi from '@/api/mall/promotion/coupon/couponTemplate' import * as CouponTemplateApi from '@/api/mall/promotion/coupon/couponTemplate'
import { floatToFixed2 } from '@/utils' import { floatToFixed2 } from '@/utils'
import { PromotionDiscountTypeEnum } from '@/utils/constants' import { CouponTemplateTakeTypeEnum, PromotionDiscountTypeEnum } from '@/utils/constants'
import CouponSelect from '@/views/mall/promotion/coupon/components/CouponSelect.vue' import CouponSelect from '@/views/mall/promotion/coupon/components/CouponSelect.vue'
// //
@ -84,7 +89,7 @@ defineOptions({ name: 'CouponCardProperty' })
const props = defineProps<{ modelValue: CouponCardProperty }>() const props = defineProps<{ modelValue: CouponCardProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
const couponList = ref<CouponTemplateApi.CouponTemplateVO[]>([]) const couponList = ref<CouponTemplateApi.CouponTemplateVO[]>([])
@ -93,10 +98,20 @@ const couponSelectDialog = ref()
const handleAddCoupon = () => { const handleAddCoupon = () => {
couponSelectDialog.value.open() couponSelectDialog.value.open()
} }
const handleCouponSelect = () => {
formData.value.couponIds = couponList.value.map((coupon) => coupon.id)
}
watch( watch(
() => couponList.value, () => formData.value.couponIds,
() => { async () => {
formData.value.couponIds = couponList.value.map((coupon) => coupon.id) if (formData.value.couponIds?.length > 0) {
couponList.value = await CouponTemplateApi.getCouponTemplateList(formData.value.couponIds)
}
},
{
immediate: true,
deep: true
} }
) )
</script> </script>

View File

@ -45,12 +45,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { DividerProperty } from './config' import { DividerProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'DividerProperty' }) defineOptions({ name: 'DividerProperty' })
const props = defineProps<{ modelValue: DividerProperty }>() const props = defineProps<{ modelValue: DividerProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
//线 //线
const BORDER_TYPES = [ const BORDER_TYPES = [

View File

@ -31,14 +31,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { FloatingActionButtonProperty } from './config' import { FloatingActionButtonProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'FloatingActionButtonProperty' }) defineOptions({ name: 'FloatingActionButtonProperty' })
const props = defineProps<{ modelValue: FloatingActionButtonProperty }>() const props = defineProps<{ modelValue: FloatingActionButtonProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -20,7 +20,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import { HotZoneProperty } from '@/components/DiyEditor/components/mobile/HotZone/config' import { HotZoneProperty } from '@/components/DiyEditor/components/mobile/HotZone/config'
import HotZoneEditDialog from './components/HotZoneEditDialog/index.vue' import HotZoneEditDialog from './components/HotZoneEditDialog/index.vue'
@ -29,7 +29,7 @@ defineOptions({ name: 'HotZoneProperty' })
const props = defineProps<{ modelValue: HotZoneProperty }>() const props = defineProps<{ modelValue: HotZoneProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
const editDialogRef = ref() const editDialogRef = ref()

View File

@ -21,14 +21,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { ImageBarProperty } from './config' import { ImageBarProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'ImageBarProperty' }) defineOptions({ name: 'ImageBarProperty' })
const props = defineProps<{ modelValue: ImageBarProperty }>() const props = defineProps<{ modelValue: ImageBarProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -56,7 +56,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import { MagicCubeProperty } from '@/components/DiyEditor/components/mobile/MagicCube/config' import { MagicCubeProperty } from '@/components/DiyEditor/components/mobile/MagicCube/config'
/** 广告魔方属性面板 */ /** 广告魔方属性面板 */
@ -64,7 +64,7 @@ defineOptions({ name: 'MagicCubeProperty' })
const props = defineProps<{ modelValue: MagicCubeProperty }>() const props = defineProps<{ modelValue: MagicCubeProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
const selectedHotAreaIndex = ref(-1) const selectedHotAreaIndex = ref(-1)

View File

@ -48,7 +48,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import { import {
EMPTY_MENU_GRID_ITEM_PROPERTY, EMPTY_MENU_GRID_ITEM_PROPERTY,
MenuGridProperty MenuGridProperty
@ -59,7 +59,7 @@ defineOptions({ name: 'MenuGridProperty' })
const props = defineProps<{ modelValue: MenuGridProperty }>() const props = defineProps<{ modelValue: MenuGridProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -28,7 +28,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import { import {
EMPTY_MENU_LIST_ITEM_PROPERTY, EMPTY_MENU_LIST_ITEM_PROPERTY,
MenuListProperty MenuListProperty
@ -39,7 +39,7 @@ defineOptions({ name: 'MenuListProperty' })
const props = defineProps<{ modelValue: MenuListProperty }>() const props = defineProps<{ modelValue: MenuListProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -58,7 +58,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import { import {
EMPTY_MENU_SWIPER_ITEM_PROPERTY, EMPTY_MENU_SWIPER_ITEM_PROPERTY,
MenuSwiperProperty MenuSwiperProperty
@ -70,7 +70,7 @@ defineOptions({ name: 'MenuSwiperProperty' })
const props = defineProps<{ modelValue: MenuSwiperProperty }>() const props = defineProps<{ modelValue: MenuSwiperProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -64,17 +64,22 @@
<script lang="ts" setup> <script lang="ts" setup>
import { NavigationBarCellProperty } from '../config' import { NavigationBarCellProperty } from '../config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'NavigationBarCellProperty' }) defineOptions({ name: 'NavigationBarCellProperty' })
const props = defineProps<{ const props = withDefaults(
modelValue: NavigationBarCellProperty[] defineProps<{
isMp: boolean modelValue: NavigationBarCellProperty[]
}>() isMp: boolean
}>(),
{
modelValue: () => [],
isMp: true
}
)
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData: cellList } = usePropertyForm(props.modelValue, emit) const cellList = useVModel(props, 'modelValue', emit)
if (!cellList.value) cellList.value = []
// 628 // 628
const cellCount = computed(() => (props.isMp ? 6 : 8)) const cellCount = computed(() => (props.isMp ? 6 : 8))

View File

@ -4,7 +4,7 @@
<div v-for="(cell, cellIndex) in cellList" :key="cellIndex" :style="getCellStyle(cell)"> <div v-for="(cell, cellIndex) in cellList" :key="cellIndex" :style="getCellStyle(cell)">
<span v-if="cell.type === 'text'">{{ cell.text }}</span> <span v-if="cell.type === 'text'">{{ cell.text }}</span>
<img v-else-if="cell.type === 'image'" :src="cell.imgUrl" alt="" class="h-full w-full" /> <img v-else-if="cell.type === 'image'" :src="cell.imgUrl" alt="" class="h-full w-full" />
<SearchBar v-else :property="getSearchProp" /> <SearchBar v-else :property="getSearchProp(cell)" />
</div> </div>
</div> </div>
<img <img
@ -51,14 +51,14 @@ const getCellStyle = (cell: NavigationBarCellProperty) => {
} as StyleValue } as StyleValue
} }
// //
const getSearchProp = (cell: NavigationBarCellProperty) => { const getSearchProp = computed(() => (cell: NavigationBarCellProperty) => {
return { return {
height: 30, height: 30,
showScan: false, showScan: false,
placeholder: cell.placeholder, placeholder: cell.placeholder,
borderRadius: cell.borderRadius borderRadius: cell.borderRadius
} as SearchProperty } as SearchProperty
} })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.navigation-bar { .navigation-bar {

View File

@ -66,7 +66,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { NavigationBarProperty } from './config' import { NavigationBarProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import NavigationBarCellProperty from '@/components/DiyEditor/components/mobile/NavigationBar/components/CellProperty.vue' import NavigationBarCellProperty from '@/components/DiyEditor/components/mobile/NavigationBar/components/CellProperty.vue'
// //
defineOptions({ name: 'NavigationBarProperty' }) defineOptions({ name: 'NavigationBarProperty' })
@ -77,7 +77,7 @@ const rules = {
const props = defineProps<{ modelValue: NavigationBarProperty }>() const props = defineProps<{ modelValue: NavigationBarProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
if (!formData.value._local) { if (!formData.value._local) {
formData.value._local = { previewMp: true, previewOther: false } formData.value._local = { previewMp: true, previewOther: false }
} }

View File

@ -30,7 +30,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { NoticeBarProperty } from './config' import { NoticeBarProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'NoticeBarProperty' }) defineOptions({ name: 'NoticeBarProperty' })
// //
@ -40,7 +40,7 @@ const rules = {
const props = defineProps<{ modelValue: NoticeBarProperty }>() const props = defineProps<{ modelValue: NoticeBarProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -20,7 +20,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { PageConfigProperty } from './config' import { PageConfigProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'PageConfigProperty' }) defineOptions({ name: 'PageConfigProperty' })
// //
@ -28,7 +28,7 @@ const rules = {}
const props = defineProps<{ modelValue: PageConfigProperty }>() const props = defineProps<{ modelValue: PageConfigProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -25,14 +25,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { PopoverProperty } from './config' import { PopoverProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// 广 // 广
defineOptions({ name: 'PopoverProperty' }) defineOptions({ name: 'PopoverProperty' })
const props = defineProps<{ modelValue: PopoverProperty }>() const props = defineProps<{ modelValue: PopoverProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -135,7 +135,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ProductCardProperty } from './config' import { ProductCardProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import SpuShowcase from '@/views/mall/product/spu/components/SpuShowcase.vue' import SpuShowcase from '@/views/mall/product/spu/components/SpuShowcase.vue'
// //
@ -143,7 +143,7 @@ defineOptions({ name: 'ProductCardProperty' })
const props = defineProps<{ modelValue: ProductCardProperty }>() const props = defineProps<{ modelValue: ProductCardProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -85,7 +85,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ProductListProperty } from './config' import { ProductListProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import SpuShowcase from '@/views/mall/product/spu/components/SpuShowcase.vue' import SpuShowcase from '@/views/mall/product/spu/components/SpuShowcase.vue'
// //
@ -93,7 +93,7 @@ defineOptions({ name: 'ProductListProperty' })
const props = defineProps<{ modelValue: ProductListProperty }>() const props = defineProps<{ modelValue: ProductListProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -25,7 +25,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { PromotionArticleProperty } from './config' import { PromotionArticleProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import * as ArticleApi from '@/api/mall/promotion/article/index' import * as ArticleApi from '@/api/mall/promotion/article/index'
// //
@ -33,7 +33,7 @@ defineOptions({ name: 'PromotionArticleProperty' })
const props = defineProps<{ modelValue: PromotionArticleProperty }>() const props = defineProps<{ modelValue: PromotionArticleProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
const articles = ref<ArticleApi.ArticleVO>([]) const articles = ref<ArticleApi.ArticleVO>([])

View File

@ -140,7 +140,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { PromotionCombinationProperty } from './config' import { PromotionCombinationProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationActivity' import * as CombinationActivityApi from '@/api/mall/promotion/combination/combinationActivity'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import CombinationShowcase from '@/views/mall/promotion/combination/components/CombinationShowcase.vue' import CombinationShowcase from '@/views/mall/promotion/combination/components/CombinationShowcase.vue'
@ -150,7 +150,7 @@ defineOptions({ name: 'PromotionCombinationProperty' })
const props = defineProps<{ modelValue: PromotionCombinationProperty }>() const props = defineProps<{ modelValue: PromotionCombinationProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
const activityList = ref<CombinationActivityApi.CombinationActivityVO[]>([]) const activityList = ref<CombinationActivityApi.CombinationActivityVO[]>([])
onMounted(async () => { onMounted(async () => {

View File

@ -140,7 +140,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { PromotionPointProperty } from './config' import { PromotionPointProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import PointShowcase from '@/views/mall/promotion/point/components/PointShowcase.vue' import PointShowcase from '@/views/mall/promotion/point/components/PointShowcase.vue'
// //
@ -148,7 +148,7 @@ defineOptions({ name: 'PromotionPointProperty' })
const props = defineProps<{ modelValue: PromotionPointProperty }>() const props = defineProps<{ modelValue: PromotionPointProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -140,7 +140,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { PromotionSeckillProperty } from './config' import { PromotionSeckillProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity' import * as SeckillActivityApi from '@/api/mall/promotion/seckill/seckillActivity'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import SeckillShowcase from '@/views/mall/promotion/seckill/components/SeckillShowcase.vue' import SeckillShowcase from '@/views/mall/promotion/seckill/components/SeckillShowcase.vue'
@ -150,7 +150,7 @@ defineOptions({ name: 'PromotionSeckillProperty' })
const props = defineProps<{ modelValue: PromotionSeckillProperty }>() const props = defineProps<{ modelValue: PromotionSeckillProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
const activityList = ref<SeckillActivityApi.SeckillActivityVO[]>([]) const activityList = ref<SeckillActivityApi.SeckillActivityVO[]>([])
onMounted(async () => { onMounted(async () => {

View File

@ -59,7 +59,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import { SearchProperty } from '@/components/DiyEditor/components/mobile/SearchBar/config' import { SearchProperty } from '@/components/DiyEditor/components/mobile/SearchBar/config'
/** 搜索框属性面板 */ /** 搜索框属性面板 */
@ -67,7 +67,7 @@ defineOptions({ name: 'SearchProperty' })
const props = defineProps<{ modelValue: SearchProperty }>() const props = defineProps<{ modelValue: SearchProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -80,13 +80,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { TabBarProperty, component, THEME_LIST } from './config' import { TabBarProperty, component, THEME_LIST } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'TabBarProperty' }) defineOptions({ name: 'TabBarProperty' })
const props = defineProps<{ modelValue: TabBarProperty }>() const props = defineProps<{ modelValue: TabBarProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
component.property.items = formData.value.items component.property.items = formData.value.items

View File

@ -101,13 +101,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { TitleBarProperty } from './config' import { TitleBarProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'TitleBarProperty' }) defineOptions({ name: 'TitleBarProperty' })
const props = defineProps<{ modelValue: TitleBarProperty }>() const props = defineProps<{ modelValue: TitleBarProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
const rules = {} const rules = {}

View File

@ -4,14 +4,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { UserCardProperty } from './config' import { UserCardProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'UserCardProperty' }) defineOptions({ name: 'UserCardProperty' })
const props = defineProps<{ modelValue: UserCardProperty }>() const props = defineProps<{ modelValue: UserCardProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -4,14 +4,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { UserCouponProperty } from './config' import { UserCouponProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'UserCouponProperty' }) defineOptions({ name: 'UserCouponProperty' })
const props = defineProps<{ modelValue: UserCouponProperty }>() const props = defineProps<{ modelValue: UserCouponProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -4,14 +4,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { UserOrderProperty } from './config' import { UserOrderProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'UserOrderProperty' }) defineOptions({ name: 'UserOrderProperty' })
const props = defineProps<{ modelValue: UserOrderProperty }>() const props = defineProps<{ modelValue: UserOrderProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -4,14 +4,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { UserWalletProperty } from './config' import { UserWalletProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'UserWalletProperty' }) defineOptions({ name: 'UserWalletProperty' })
const props = defineProps<{ modelValue: UserWalletProperty }>() const props = defineProps<{ modelValue: UserWalletProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -42,14 +42,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { VideoPlayerProperty } from './config' import { VideoPlayerProperty } from './config'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
// //
defineOptions({ name: 'VideoPlayerProperty' }) defineOptions({ name: 'VideoPlayerProperty' })
const props = defineProps<{ modelValue: VideoPlayerProperty }>() const props = defineProps<{ modelValue: VideoPlayerProperty }>()
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -110,7 +110,7 @@
<el-tag <el-tag
v-if="showPageConfig" v-if="showPageConfig"
:effect="selectedComponent?.uid === pageConfigComponent.uid ? 'dark' : 'plain'" :effect="selectedComponent?.uid === pageConfigComponent.uid ? 'dark' : 'plain'"
:type="selectedComponent?.uid === pageConfigComponent.uid ? '' : 'info'" :type="selectedComponent?.uid === pageConfigComponent.uid ? 'primary' : 'info'"
size="large" size="large"
@click="handleComponentSelected(pageConfigComponent)" @click="handleComponentSelected(pageConfigComponent)"
> >
@ -121,7 +121,7 @@
<el-tag <el-tag
v-if="component.position === 'fixed'" v-if="component.position === 'fixed'"
:effect="selectedComponent?.uid === component.uid ? 'dark' : 'plain'" :effect="selectedComponent?.uid === component.uid ? 'dark' : 'plain'"
:type="selectedComponent?.uid === component.uid ? '' : 'info'" :type="selectedComponent?.uid === component.uid ? 'primary' : 'info'"
closable closable
size="large" size="large"
@click="handleComponentSelected(component)" @click="handleComponentSelected(component)"
@ -191,7 +191,7 @@ import { cloneDeep, includes } from 'lodash-es'
import { component as PAGE_CONFIG_COMPONENT } from '@/components/DiyEditor/components/mobile/PageConfig/config' import { component as PAGE_CONFIG_COMPONENT } from '@/components/DiyEditor/components/mobile/PageConfig/config'
import { component as NAVIGATION_BAR_COMPONENT } from './components/mobile/NavigationBar/config' import { component as NAVIGATION_BAR_COMPONENT } from './components/mobile/NavigationBar/config'
import { component as TAB_BAR_COMPONENT } from './components/mobile/TabBar/config' import { component as TAB_BAR_COMPONENT } from './components/mobile/TabBar/config'
import { isString } from '@/utils/is' import { isEmpty, isString } from '@/utils/is'
import { DiyComponent, DiyComponentLibrary, PageConfig } from '@/components/DiyEditor/util' import { DiyComponent, DiyComponentLibrary, PageConfig } from '@/components/DiyEditor/util'
import { componentConfigs } from '@/components/DiyEditor/components/mobile' import { componentConfigs } from '@/components/DiyEditor/components/mobile'
import { array, oneOfType } from 'vue-types' import { array, oneOfType } from 'vue-types'
@ -238,24 +238,42 @@ const props = defineProps({
watch( watch(
() => props.modelValue, () => props.modelValue,
() => { () => {
const modelValue = isString(props.modelValue) const modelValue =
? (JSON.parse(props.modelValue) as PageConfig) isString(props.modelValue) && !isEmpty(props.modelValue)
: props.modelValue ? (JSON.parse(props.modelValue) as PageConfig)
pageConfigComponent.value.property = modelValue?.page || PAGE_CONFIG_COMPONENT.property : props.modelValue
pageConfigComponent.value.property =
(typeof modelValue !== 'string' && modelValue?.page) || PAGE_CONFIG_COMPONENT.property
navigationBarComponent.value.property = navigationBarComponent.value.property =
modelValue?.navigationBar || NAVIGATION_BAR_COMPONENT.property (typeof modelValue !== 'string' && modelValue?.navigationBar) ||
tabBarComponent.value.property = modelValue?.tabBar || TAB_BAR_COMPONENT.property NAVIGATION_BAR_COMPONENT.property
tabBarComponent.value.property =
(typeof modelValue !== 'string' && modelValue?.tabBar) || TAB_BAR_COMPONENT.property
// //
pageComponents.value = (modelValue?.components || []).map((item) => { pageComponents.value = ((typeof modelValue !== 'string' && modelValue?.components) || []).map(
const component = componentConfigs[item.id] (item) => {
return { ...component, property: item.property } const component = componentConfigs[item.id]
}) return { ...component, property: item.property }
}
)
}, },
{ {
immediate: true immediate: true
} }
) )
/** 选择组件修改其属性后更新它的配置 */
watch(
selectedComponent,
(val: any) => {
if (!val || selectedComponentIndex.value === -1) {
return
}
pageComponents.value[selectedComponentIndex.value] = selectedComponent.value!
},
{ deep: true }
)
// //
const handleSave = () => { const handleSave = () => {
// //

View File

@ -1,4 +1,3 @@
import { ref, Ref } from 'vue'
import { PageConfigProperty } from '@/components/DiyEditor/components/mobile/PageConfig/config' import { PageConfigProperty } from '@/components/DiyEditor/components/mobile/PageConfig/config'
import { NavigationBarProperty } from '@/components/DiyEditor/components/mobile/NavigationBar/config' import { NavigationBarProperty } from '@/components/DiyEditor/components/mobile/NavigationBar/config'
import { TabBarProperty } from '@/components/DiyEditor/components/mobile/TabBar/config' import { TabBarProperty } from '@/components/DiyEditor/components/mobile/TabBar/config'
@ -78,34 +77,6 @@ export interface PageConfig {
// 页面组件只保留组件ID组件属性 // 页面组件只保留组件ID组件属性
export interface PageComponent extends Pick<DiyComponent<any>, 'id' | 'property'> {} export interface PageComponent extends Pick<DiyComponent<any>, 'id' | 'property'> {}
// 属性表单监听
export function usePropertyForm<T>(modelValue: T, emit: Function): { formData: Ref<T> } {
const formData = ref<T>()
// 监听属性数据变动
watch(
() => modelValue,
() => {
formData.value = modelValue
},
{
deep: true,
immediate: true
}
)
// 监听表单数据变动
watch(
() => formData.value,
() => {
emit('update:modelValue', formData.value)
},
{
deep: true
}
)
return { formData } as { formData: Ref<T> }
}
// 页面组件库 // 页面组件库
export const PAGE_LIBS = [ export const PAGE_LIBS = [
{ {

View File

@ -13,9 +13,16 @@
class="mb-4px flex flex-col gap-4px border border-gray-2 border-rounded rounded border-solid p-8px" class="mb-4px flex flex-col gap-4px border border-gray-2 border-rounded rounded border-solid p-8px"
> >
<!-- 操作按钮区 --> <!-- 操作按钮区 -->
<div class="m--8px m-b-4px flex flex-row items-center justify-between p-8px" style="background-color: var(--app-content-bg-color);"> <div
class="m--8px m-b-4px flex flex-row items-center justify-between p-8px"
style="background-color: var(--app-content-bg-color)"
>
<el-tooltip content="拖动排序"> <el-tooltip content="拖动排序">
<Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" style="color: #8a909c;" /> <Icon
icon="ic:round-drag-indicator"
class="drag-icon cursor-move"
style="color: #8a909c"
/>
</el-tooltip> </el-tooltip>
<el-tooltip content="删除"> <el-tooltip content="删除">
<Icon <Icon
@ -47,7 +54,7 @@
<script setup lang="ts"> <script setup lang="ts">
// //
import VueDraggable from 'vuedraggable' import VueDraggable from 'vuedraggable'
import { usePropertyForm } from '@/components/DiyEditor/util' import { useVModel } from '@vueuse/core'
import { any, array } from 'vue-types' import { any, array } from 'vue-types'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
@ -66,7 +73,7 @@ const props = defineProps({
}) })
// //
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit) const formData = useVModel(props, 'modelValue', emit)
// //
const handleAdd = () => formData.value.push(cloneDeep(props.emptyItem || {})) const handleAdd = () => formData.value.push(cloneDeep(props.emptyItem || {}))

View File

@ -75,7 +75,7 @@ watch(
<template> <template>
<ElIcon :class="prefixCls" :color="color" :size="size"> <ElIcon :class="prefixCls" :color="color" :size="size">
<svg v-if="isLocal" :class="getSvgClass" aria-hidden="true"> <svg v-if="isLocal" :class="getSvgClass">
<use :xlink:href="symbolId" /> <use :xlink:href="symbolId" />
</svg> </svg>

View File

@ -1,7 +1,7 @@
<template> <template>
<el-input v-model="valueRef" v-bind="$attrs"> <el-input v-model="modelValue" v-bind="$attrs">
<template #append> <template #append>
<el-color-picker v-model="colorRef" :predefine="PREDEFINE_COLORS" /> <el-color-picker v-model="color" :predefine="PREDEFINE_COLORS" />
</template> </template>
</el-input> </el-input>
</template> </template>
@ -9,6 +9,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { PREDEFINE_COLORS } from '@/utils/color' import { PREDEFINE_COLORS } from '@/utils/color'
import { useVModels } from '@vueuse/core'
/** /**
* 带颜色选择器输入框 * 带颜色选择器输入框
@ -19,33 +20,8 @@ const props = defineProps({
modelValue: propTypes.string.def('').isRequired, modelValue: propTypes.string.def('').isRequired,
color: propTypes.string.def('').isRequired color: propTypes.string.def('').isRequired
}) })
watch(
() => props.modelValue,
(val: string) => {
if (val === unref(valueRef)) return
valueRef.value = val
}
)
const emit = defineEmits(['update:modelValue', 'update:color']) const emit = defineEmits(['update:modelValue', 'update:color'])
const { modelValue, color } = useVModels(props, emit)
//
const valueRef = ref(props.modelValue)
watch(
() => valueRef.value,
(val: string) => {
emit('update:modelValue', val)
}
)
//
const colorRef = ref(props.color)
watch(
() => colorRef.value,
(val: string) => {
emit('update:color', val)
}
)
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
:deep(.el-input-group__append) { :deep(.el-input-group__append) {

View File

@ -25,7 +25,6 @@
<script setup lang="ts"> <script setup lang="ts">
import SimpleProcessModel from './SimpleProcessModel.vue' import SimpleProcessModel from './SimpleProcessModel.vue'
import { updateBpmSimpleModel, getBpmSimpleModel } from '@/api/bpm/simple'
import { SimpleFlowNode, NodeType, NodeId, NODE_DEFAULT_TEXT } from './consts' import { SimpleFlowNode, NodeType, NodeId, NODE_DEFAULT_TEXT } from './consts'
import { getModel } from '@/api/bpm/model' import { getModel } from '@/api/bpm/model'
import { getForm, FormVO } from '@/api/bpm/form' import { getForm, FormVO } from '@/api/bpm/form'
@ -35,6 +34,7 @@ import * as DeptApi from '@/api/system/dept'
import * as PostApi from '@/api/system/post' import * as PostApi from '@/api/system/post'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import * as UserGroupApi from '@/api/bpm/userGroup' import * as UserGroupApi from '@/api/bpm/userGroup'
import { BpmModelFormType } from '@/utils/constants'
defineOptions({ defineOptions({
name: 'SimpleProcessDesigner' name: 'SimpleProcessDesigner'
@ -168,7 +168,7 @@ onMounted(async () => {
const bpmnModel = await getModel(props.modelId) const bpmnModel = await getModel(props.modelId)
if (bpmnModel) { if (bpmnModel) {
formType.value = bpmnModel.formType formType.value = bpmnModel.formType
if (formType.value === 10) { if (formType.value === BpmModelFormType.NORMAL && bpmnModel.formId) {
const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO
formFields.value = bpmnForm?.fields formFields.value = bpmnForm?.fields
} }

View File

@ -1,4 +1,5 @@
<!-- 列表选择通用组件参考 ProductList 组件使用 --> <!-- 列表选择通用组件参考 ProductList 组件使用 -->
<!-- TODO 芋艿可能会移除 -->
<template> <template>
<Dialog v-model="dialogVisible" :appendToBody="true" :scroll="true" :title="title" width="60%"> <Dialog v-model="dialogVisible" :appendToBody="true" :scroll="true" :title="title" width="60%">
<el-table <el-table

View File

@ -449,3 +449,18 @@ export function jsonParse(str: string) {
return '' return ''
} }
} }
/**
*
*
* @param name
* @param start
* @param end
*/
export const sliceName = (name: string,start: number, end : number) => {
if (name.length > end) {
return name.slice(start, end)
}
return name
}

View File

@ -88,6 +88,9 @@
/> />
</el-tooltip> </el-tooltip>
<el-image v-if="row.icon" :src="row.icon" class="h-38px w-38px mr-10px rounded" /> <el-image v-if="row.icon" :src="row.icon" class="h-38px w-38px mr-10px rounded" />
<div v-else class="flow-icon">
<span style="font-size: 12px; color: #fff">{{ sliceName(row.name,0,2) }}</span>
</div>
{{ row.name }} {{ row.name }}
</div> </div>
</template> </template>
@ -249,6 +252,11 @@
</div> </div>
</template> </template>
</Dialog> </Dialog>
<!-- 弹窗表单详情 -->
<Dialog title="表单详情" :fullscreen="true" v-model="formDetailVisible">
<form-create :rule="formDetailPreview.rule" :option="formDetailPreview.option" />
</Dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -265,6 +273,7 @@ import { useAppStore } from '@/store/modules/app'
import { cloneDeep, isEqual } from 'lodash-es' import { cloneDeep, isEqual } from 'lodash-es'
import { useTagsView } from '@/hooks/web/useTagsView' import { useTagsView } from '@/hooks/web/useTagsView'
import { useDebounceFn } from '@vueuse/core' import { useDebounceFn } from '@vueuse/core'
import { sliceName } from '@/utils/index'
defineOptions({ name: 'BpmModel' }) defineOptions({ name: 'BpmModel' })
@ -437,11 +446,10 @@ const handleChangeState = async (row: any) => {
/** 发布流程 */ /** 发布流程 */
const handleDeploy = async (row: any) => { const handleDeploy = async (row: any) => {
try { try {
// await message.confirm('是否确认发布该流程?')
await message.confirm('是否部署该流程!!')
// //
await ModelApi.deployModel(row.id) await ModelApi.deployModel(row.id)
message.success(t('部署成功')) message.success(t('发布成功'))
// //
emit('success') emit('success')
} catch {} } catch {}
@ -464,7 +472,7 @@ const formDetailPreview = ref({
option: {} option: {}
}) })
const handleFormDetail = async (row: any) => { const handleFormDetail = async (row: any) => {
if (row.formType == 10) { if (row.formType == BpmModelFormType.NORMAL) {
// //
const data = await FormApi.getForm(row.formId) const data = await FormApi.getForm(row.formId)
setConfAndFields2(formDetailPreview, data.conf, data.fields) setConfAndFields2(formDetailPreview, data.conf, data.fields)
@ -617,6 +625,17 @@ watchEffect(() => {
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.flow-icon {
display: flex;
width: 38px;
height: 38px;
margin-right: 10px;
background-color: var(--el-color-primary);
border-radius: 0.25rem;
align-items: center;
justify-content: center;
}
.category-draggable-model { .category-draggable-model {
:deep(.el-table__cell) { :deep(.el-table__cell) {
overflow: hidden; overflow: hidden;

View File

@ -6,7 +6,7 @@
class="!w-440px" class="!w-440px"
v-model="modelData.key" v-model="modelData.key"
:disabled="!!modelData.id" :disabled="!!modelData.id"
placeholder="请输入流标标识" placeholder="请输入流程标识,以字母或下划线开头"
/> />
<el-tooltip <el-tooltip
class="item" class="item"
@ -41,7 +41,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="流程图标" prop="icon" class="mb-20px"> <el-form-item label="流程图标" class="mb-20px">
<UploadImg v-model="modelData.icon" :limit="1" height="64px" width="64px" /> <UploadImg v-model="modelData.icon" :limit="1" height="64px" width="64px" />
</el-form-item> </el-form-item>
<el-form-item label="流程描述" prop="description" class="mb-20px"> <el-form-item label="流程描述" prop="description" class="mb-20px">
@ -155,7 +155,6 @@ const rules = {
name: [{ required: true, message: '流程名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '流程名称不能为空', trigger: 'blur' }],
key: [{ required: true, message: '流程标识不能为空', trigger: 'blur' }], key: [{ required: true, message: '流程标识不能为空', trigger: 'blur' }],
category: [{ required: true, message: '流程分类不能为空', trigger: 'blur' }], category: [{ required: true, message: '流程分类不能为空', trigger: 'blur' }],
icon: [{ required: true, message: '流程图标不能为空', trigger: 'blur' }],
type: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }], type: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }],
visible: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }], visible: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }],
managerUserIds: [{ required: true, message: '流程管理员不能为空', trigger: 'blur' }] managerUserIds: [{ required: true, message: '流程管理员不能为空', trigger: 'blur' }]

View File

@ -285,9 +285,8 @@ const handleSave = async () => {
} else { } else {
// //
formData.value.id = await ModelApi.createModel(modelData) formData.value.id = await ModelApi.createModel(modelData)
message.success('新增成功')
try { try {
await message.confirm('创建流程成功,是否继续编辑?') await message.confirm('流程创建成功,是否继续编辑?')
// //
await nextTick() await nextTick()
// //
@ -317,7 +316,6 @@ const handleDeploy = async () => {
if (!formData.value.id) { if (!formData.value.id) {
await message.confirm('是否确认发布该流程?') await message.confirm('是否确认发布该流程?')
} }
// //
await validateAllSteps() await validateAllSteps()

View File

@ -58,7 +58,16 @@
> >
<template #default> <template #default>
<div class="flex"> <div class="flex">
<el-image :src="definition.icon" class="w-32px h-32px" /> <el-image
v-if="definition.icon"
:src="definition.icon"
class="w-32px h-32px"
/>
<div v-else class="flow-icon">
<span style="font-size: 12px; color: #fff">{{
sliceName(definition.name,0,2)
}}</span>
</div>
<el-text class="!ml-10px" size="large">{{ definition.name }}</el-text> <el-text class="!ml-10px" size="large">{{ definition.name }}</el-text>
</div> </div>
</template> </template>
@ -88,6 +97,7 @@ import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import { CategoryApi, CategoryVO } from '@/api/bpm/category' import { CategoryApi, CategoryVO } from '@/api/bpm/category'
import ProcessDefinitionDetail from './ProcessDefinitionDetail.vue' import ProcessDefinitionDetail from './ProcessDefinitionDetail.vue'
import { groupBy } from 'lodash-es' import { groupBy } from 'lodash-es'
import { sliceName } from '@/utils/index'
defineOptions({ name: 'BpmProcessInstanceCreate' }) defineOptions({ name: 'BpmProcessInstanceCreate' })
@ -282,13 +292,25 @@ onMounted(() => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.flow-icon {
display: flex;
width: 32px;
height: 32px;
margin-right: 10px;
background-color: var(--el-color-primary);
border-radius: 0.25rem;
align-items: center;
justify-content: center;
}
.process-definition-container::before { .process-definition-container::before {
content: '';
border-left: 1px solid #e6e6e6;
position: absolute; position: absolute;
left: 20.8%; left: 20.8%;
height: 100%; height: 100%;
border-left: 1px solid #e6e6e6;
content: '';
} }
:deep() { :deep() {
.definition-item-card { .definition-item-card {
.el-card__body { .el-card__body {

View File

@ -66,7 +66,11 @@
</el-table-column> </el-table-column>
<el-table-column label="产品单价" fixed="right" min-width="120"> <el-table-column label="产品单价" fixed="right" min-width="120">
<template #default="{ row, $index }"> <template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productPrice`" class="mb-0px!"> <el-form-item
:prop="`${$index}.productPrice`"
:rules="formRules.productPrice"
class="mb-0px!"
>
<el-input-number <el-input-number
v-model="row.productPrice" v-model="row.productPrice"
controls-position="right" controls-position="right"
@ -153,6 +157,7 @@ const formLoading = ref(false) // 表单的加载中
const formData = ref([]) const formData = ref([])
const formRules = reactive({ const formRules = reactive({
productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }], productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }],
productPrice: [{ required: true, message: '产品单价不能为空', trigger: 'blur' }],
count: [{ required: true, message: '产品数量不能为空', trigger: 'blur' }] count: [{ required: true, message: '产品数量不能为空', trigger: 'blur' }]
}) })
const formRef = ref([]) // Ref const formRef = ref([]) // Ref

View File

@ -7,7 +7,7 @@
<el-descriptions-item label="任务名称"> <el-descriptions-item label="任务名称">
{{ detailData.name }} {{ detailData.name }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="任务名称"> <el-descriptions-item label="任务状态">
<dict-tag :type="DICT_TYPE.INFRA_JOB_STATUS" :value="detailData.status" /> <dict-tag :type="DICT_TYPE.INFRA_JOB_STATUS" :value="detailData.status" />
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="处理器的名字"> <el-descriptions-item label="处理器的名字">

View File

@ -52,7 +52,9 @@ const formLoading = ref(false) // 表单的加载中1修改时的数据加
const formData = ref<DiyTemplateApi.DiyTemplatePropertyVO>() const formData = ref<DiyTemplateApi.DiyTemplatePropertyVO>()
const formRef = ref() // Ref const formRef = ref() // Ref
// //
const currentFormData = ref<DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO>() const currentFormData = ref<DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO>({
property: ''
} as DiyPageApi.DiyPageVO)
// templateItem // templateItem
const currentFormDataMap = ref< const currentFormDataMap = ref<
Map<string, DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO> Map<string, DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO>
@ -92,17 +94,21 @@ const handleTemplateItemChange = (val: number) => {
// //
if (val === 0) { if (val === 0) {
libs.value = templateLibs libs.value = templateLibs
currentFormData.value = isEmpty(data) ? formData.value : data currentFormData.value = (isEmpty(data) ? formData.value : data) as
| DiyTemplateApi.DiyTemplatePropertyVO
| DiyPageApi.DiyPageVO
return return
} }
// //
libs.value = PAGE_LIBS libs.value = PAGE_LIBS
currentFormData.value = isEmpty(data) currentFormData.value = (
? formData.value!.pages.find( isEmpty(data)
(page: DiyPageApi.DiyPageVO) => page.name === templateItems[val].name ? formData.value!.pages.find(
) (page: DiyPageApi.DiyPageVO) => page.name === templateItems[val].name
: data )
: data
) as DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO
} }
// //
@ -170,7 +176,9 @@ const recoverPageIndex = () => {
sessionStorage.removeItem(DIY_PAGE_INDEX_KEY) sessionStorage.removeItem(DIY_PAGE_INDEX_KEY)
// //
currentFormData.value = formData.value currentFormData.value = formData.value as
| DiyTemplateApi.DiyTemplatePropertyVO
| DiyPageApi.DiyPageVO
currentFormDataMap.value = new Map< currentFormDataMap.value = new Map<
string, string,
DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO

View File

@ -279,8 +279,9 @@ const handleSendMessage = async (event: any) => {
return return
} }
// 1. // 1.
if (isEmpty(unref(message.value))) { if (isEmpty(unref(message.value)?.trim())) {
messageTool.notifyWarning('请输入消息后再发送哦!') messageTool.notifyWarning('请输入消息后再发送哦!')
message.value = ''
return return
} }
// 2. // 2.

View File

@ -37,40 +37,45 @@ const { data, close, open } = useWebSocket(server.value, {
}) })
/** 监听 WebSocket 数据 */ /** 监听 WebSocket 数据 */
watchEffect(() => { watch(
if (!data.value) { () => data.value,
return (newData) => {
if (!newData) return
try {
// 1.
if (newData === 'pong') return
// 2.1 type
const jsonMessage = JSON.parse(newData)
const type = jsonMessage.type
if (!type) {
message.error('未知的消息类型:' + newData)
return
}
// 2.2 KEFU_MESSAGE_TYPE
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_TYPE) {
const message = JSON.parse(jsonMessage.content)
//
kefuStore.updateConversation(message.conversationId)
//
keFuChatBoxRef.value?.refreshMessageList(message)
return
}
// 2.3 KEFU_MESSAGE_ADMIN_READ
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_ADMIN_READ) {
//
kefuStore.updateConversationStatus(jsonParse(jsonMessage.content))
}
} catch (error) {
console.error(error)
}
},
{
immediate: false //
} }
try { )
// 1.
if (data.value === 'pong') {
return
}
// 2.1 type
const jsonMessage = JSON.parse(data.value)
const type = jsonMessage.type
if (!type) {
message.error('未知的消息类型:' + data.value)
return
}
// 2.2 KEFU_MESSAGE_TYPE
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_TYPE) {
const message = JSON.parse(jsonMessage.content)
//
kefuStore.updateConversation(message.conversationId)
//
keFuChatBoxRef.value?.refreshMessageList(message)
return
}
// 2.3 KEFU_MESSAGE_ADMIN_READ
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_ADMIN_READ) {
//
kefuStore.updateConversationStatus(jsonParse(jsonMessage.content))
}
} catch (error) {
console.error(error)
}
})
// ======================= WebSocket end ======================= // ======================= WebSocket end =======================
/** 加载指定会话的消息列表 */ /** 加载指定会话的消息列表 */

View File

@ -26,9 +26,23 @@
placeholder="请输入微信 APPID" placeholder="请输入微信 APPID"
/> />
</el-form-item> </el-form-item>
<el-form-item label-width="180px">
<a
href="https://pay.weixin.qq.com/index.php/extend/merchant_appid/mapay_platform/account_manage"
target="_blank"
>
前往微信商户平台查看 APPID
</a>
</el-form-item>
<el-form-item label="商户号" label-width="180px" prop="config.mchId"> <el-form-item label="商户号" label-width="180px" prop="config.mchId">
<el-input v-model="formData.config.mchId" :style="{ width: '100%' }" /> <el-input v-model="formData.config.mchId" :style="{ width: '100%' }" />
</el-form-item> </el-form-item>
<el-form-item label-width="180px">
<a href="https://pay.weixin.qq.com/index.php/extend/pay_setting" target="_blank">
前往微信商户平台查看商户号
</a>
</el-form-item>
<el-form-item label="渠道状态" label-width="180px" prop="status"> <el-form-item label="渠道状态" label-width="180px" prop="status">
<el-radio-group v-model="formData.status"> <el-radio-group v-model="formData.status">
<el-radio <el-radio
@ -123,6 +137,14 @@
placeholder="请输入证书序列号" placeholder="请输入证书序列号"
/> />
</el-form-item> </el-form-item>
<el-form-item label-width="180px">
<a
href="https://pay.weixin.qq.com/index.php/core/cert/api_cert#/api-cert-manage"
target="_blank"
>
前往微信商户平台查看证书序列号
</a>
</el-form-item>
</div> </div>
<el-form-item label="备注" label-width="180px" prop="remark"> <el-form-item label="备注" label-width="180px" prop="remark">
<el-input v-model="formData.remark" :style="{ width: '100%' }" /> <el-input v-model="formData.remark" :style="{ width: '100%' }" />

View File

@ -53,6 +53,10 @@
<Icon class="mr-5px" icon="ep:plus" /> <Icon class="mr-5px" icon="ep:plus" />
新增 新增
</el-button> </el-button>
<el-button plain type="danger" @click="toggleExpandAll">
<Icon class="mr-5px" icon="ep:sort" />
展开/折叠
</el-button>
<el-button plain @click="refreshMenu"> <el-button plain @click="refreshMenu">
<Icon class="mr-5px" icon="ep:refresh" /> <Icon class="mr-5px" icon="ep:refresh" />
刷新菜单缓存 刷新菜单缓存
@ -63,149 +67,169 @@
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<div style="height: 700px"> <el-auto-resizer>
<!-- AutoResizer 自动调节大小 --> <template #default="{ width }">
<el-auto-resizer> <el-table-v2
<template #default="{ height, width }"> v-model:expanded-row-keys="expandedRowKeys"
<!-- Virtualized Table 虚拟化表格高性能解决表格在大数据量下的卡顿问题 --> :columns="columns"
<el-table-v2 :data="list"
v-loading="loading" :expand-column-key="columns[0].key"
:columns="columns" :height="1000"
:data="list" :width="width"
:width="width" fixed
:height="height" row-key="id"
expand-column-key="name" />
/> </template>
</template> </el-auto-resizer>
</el-auto-resizer>
</div>
</ContentWrap> </ContentWrap>
<!-- 表单弹窗添加/修改 --> <!-- 表单弹窗添加/修改 -->
<MenuForm ref="formRef" @success="getList" /> <MenuForm ref="formRef" @success="getList" />
</template> </template>
<script lang="ts" setup> <script lang="tsx" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { handleTree } from '@/utils/tree' import { handleTree } from '@/utils/tree'
import * as MenuApi from '@/api/system/menu' import * as MenuApi from '@/api/system/menu'
import { MenuVO } from '@/api/system/menu' import { MenuVO } from '@/api/system/menu'
import MenuForm from './MenuForm.vue' import MenuForm from './MenuForm.vue'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache' import DictTag from '@/components/DictTag/src/DictTag.vue'
import { h } from 'vue'
import { Column, ElButton } from 'element-plus'
import { Icon } from '@/components/Icon' import { Icon } from '@/components/Icon'
import { hasPermission } from '@/directives/permission/hasPermi' import { ElButton, TableV2FixedDir } from 'element-plus'
import { checkPermi } from '@/utils/permission'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
defineOptions({ name: 'SystemMenu' }) defineOptions({ name: 'SystemMenu' })
//
const columns = [
{
key: 'name',
title: '菜单名称',
dataKey: 'name',
width: 250,
fixed: TableV2FixedDir.LEFT
},
{
key: 'icon',
title: '图标',
dataKey: 'icon',
width: 100,
align: 'center',
cellRenderer: ({ cellData: icon }) => <Icon icon={icon} />
},
{
key: 'sort',
title: '排序',
dataKey: 'sort',
width: 60
},
{
key: 'permission',
title: '权限标识',
dataKey: 'permission',
width: 300
},
{
key: 'component',
title: '组件路径',
dataKey: 'component',
width: 500
},
{
key: 'componentName',
title: '组件名称',
dataKey: 'componentName',
width: 200
},
{
key: 'status',
title: '状态',
dataKey: 'status',
width: 60,
fixed: TableV2FixedDir.RIGHT,
cellRenderer: ({ rowData }) => {
//
if (!checkPermi(['system:menu:update'])) {
return <DictTag type={DICT_TYPE.COMMON_STATUS} value={rowData.status} />
}
// ElSwitch
return (
<ElSwitch
v-model={rowData.status}
active-value={CommonStatusEnum.ENABLE}
inactive-value={CommonStatusEnum.DISABLE}
loading={menuStatusUpdating[rowData.id]}
class="ml-4px"
onChange={(val) => handleStatusChanged(rowData, val)}
/>
)
}
},
{
key: 'operations',
title: '操作',
align: 'center',
width: 160,
fixed: TableV2FixedDir.RIGHT,
cellRenderer: ({ rowData }) => {
//
const buttons = []
//
if (checkPermi(['system:menu:update'])) {
buttons.push(
<ElButton key="edit" link type="primary" onClick={() => openForm('update', rowData.id)}>
修改
</ElButton>
)
}
if (checkPermi(['system:menu:create'])) {
buttons.push(
<ElButton
key="create"
link
type="primary"
onClick={() => openForm('create', undefined, rowData.id)}
>
新增
</ElButton>
)
}
if (checkPermi(['system:menu:delete'])) {
buttons.push(
<ElButton key="delete" link type="danger" onClick={() => handleDelete(rowData.id)}>
删除
</ElButton>
)
}
// null
if (buttons.length === 0) {
return null
}
//
return <>{buttons}</>
}
}
]
const { wsCache } = useCache() const { wsCache } = useCache()
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
// column
const columns: Column[] = [
{
dataKey: 'name',
title: '菜单名称',
width: 250
},
{
dataKey: 'icon',
title: '图标',
width: 150,
cellRenderer: ({ rowData }) => {
return h(Icon, {
icon: rowData.icon
})
}
},
{
dataKey: 'sort',
title: '排序',
width: 100
},
{
dataKey: 'permission',
title: '权限标识',
width: 240
},
{
dataKey: 'component',
title: '组件路径',
width: 240
},
{
dataKey: 'componentName',
title: '组件名称',
width: 240
},
{
dataKey: 'status',
title: '状态',
width: 160,
cellRenderer: ({ rowData }) => {
return h(ElSwitch, {
modelValue: rowData.status,
activeValue: CommonStatusEnum.ENABLE,
inactiveValue: CommonStatusEnum.DISABLE,
loading: menuStatusUpdating.value[rowData.id],
disabled: !hasPermission(['system:menu:update']),
onChange: (val) => handleStatusChanged(rowData, val as number)
})
}
},
{
dataKey: 'operation',
title: '操作',
width: 200,
cellRenderer: ({ rowData }) => {
return h(
'div',
{},
[
hasPermission(['system:menu:update']) &&
h(
ElButton,
{
link: true,
type: 'primary',
onClick: () => openForm('update', rowData.id)
},
() => '修改'
),
hasPermission(['system:menu:create']) &&
h(
ElButton,
{
link: true,
type: 'primary',
onClick: () => openForm('create', undefined, rowData.id)
},
() => '新增'
),
hasPermission(['system:menu:delete']) &&
h(
ElButton,
{
link: true,
type: 'danger',
onClick: () => handleDelete(rowData.id)
},
() => '删除'
)
].filter(Boolean)
)
}
}
]
const loading = ref(true) // const loading = ref(true) //
const list = ref<any>([]) // const list = ref<any[]>([]) //
const queryParams = reactive({ const queryParams = reactive({
name: undefined, name: undefined,
status: undefined status: undefined
}) })
const queryFormRef = ref() // const queryFormRef = ref() //
const isExpandAll = ref(false) //
const refreshTable = ref(true) //
//
const expandedRowKeys = ref<number[]>([])
/** 查询列表 */ /** 查询列表 */
const getList = async () => { const getList = async () => {
@ -235,6 +259,18 @@ const openForm = (type: string, id?: number, parentId?: number) => {
formRef.value.open(type, id, parentId) formRef.value.open(type, id, parentId)
} }
/** 展开/折叠操作 */
const toggleExpandAll = () => {
if (!isExpandAll.value) {
//
expandedRowKeys.value = list.value.map((item) => item.id)
} else {
//
expandedRowKeys.value = []
}
isExpandAll.value = !isExpandAll.value
}
/** 刷新菜单缓存按钮操作 */ /** 刷新菜单缓存按钮操作 */
const refreshMenu = async () => { const refreshMenu = async () => {
try { try {

View File

@ -124,6 +124,7 @@
:active-value="0" :active-value="0"
:inactive-value="1" :inactive-value="1"
@change="handleStatusChange(scope.row)" @change="handleStatusChange(scope.row)"
:disabled="!checkPermi(['system:user:update'])"
/> />
</template> </template>
</el-table-column> </el-table-column>