init
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
<script setup lang="ts">
|
||||
import type { PropType } from 'vue'
|
||||
import { defineComponent, onMounted, ref } from 'vue'
|
||||
import { PREFIX } from '../../_constants'
|
||||
import { useTranslate } from '../../../locale'
|
||||
import NutIcon from '../../icon/icon.vue'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: 'base', // simple,base,complex
|
||||
},
|
||||
info: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
operation: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => ['replay', 'like', 'more'],
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['clickOperate', 'handleClick'])
|
||||
|
||||
const showPopver = ref(false)
|
||||
|
||||
const mergeOp = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
const deOp = ['replay', 'like', 'more']
|
||||
|
||||
if (props.operation) {
|
||||
props.operation.forEach((name: string) => {
|
||||
if (deOp.includes(name))
|
||||
(mergeOp.value as any).push(name)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
function operate(type: string) {
|
||||
if (type === 'more')
|
||||
showPopver.value = !showPopver.value
|
||||
|
||||
emit('clickOperate', type)
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
emit('handleClick')
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
const componentName = `${PREFIX}-comment-bottom`
|
||||
const { translate } = useTranslate(componentName)
|
||||
export default defineComponent ({
|
||||
name: componentName,
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="nut-comment-bottom">
|
||||
<view class="nut-comment-bottom__lable" @click="handleClick">
|
||||
<span v-if="type !== 'complex'" style="display: inline;white-space:none;">
|
||||
{{ info.size }}
|
||||
</span>
|
||||
</view>
|
||||
|
||||
<view class="nut-comment-bottom__cpx">
|
||||
<template v-for="(name, i) in mergeOp" :key="i">
|
||||
<view class="nut-comment-bottom__cpx-item" :class="[`nut-comment-bottom__cpx-item--${name}`]" @click="operate(name)">
|
||||
<template v-if="name !== 'more'">
|
||||
<text>{{ info[name] }}</text>
|
||||
<NutIcon v-if="name === 'like'" name="fabulous" />
|
||||
<NutIcon v-else name="comment" />
|
||||
</template>
|
||||
<template v-if="name === 'more'">
|
||||
<NutIcon name="more-x" />
|
||||
<view v-if="showPopver" class="nut-comment-bottom__cpx-item-popover" @click="operate('popover')">
|
||||
{{
|
||||
translate('complaintsText')
|
||||
}}
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.nut-theme-dark {
|
||||
.nut-comment {
|
||||
&-bottom {
|
||||
&__cpx {
|
||||
color: $dark-color;
|
||||
|
||||
&-item {
|
||||
text {
|
||||
color: $dark-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nut-comment {
|
||||
&-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-right: 5px;
|
||||
color: $comment-bottom-label-color;
|
||||
|
||||
&__lable {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
|
||||
// stylelint-disable-next-line at-rule-no-unknown
|
||||
@include oneline-ellipsis;
|
||||
}
|
||||
|
||||
&__cpx {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
color: $black;
|
||||
|
||||
&-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 18px;
|
||||
|
||||
text {
|
||||
margin-right: 5px;
|
||||
color: $black;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&-popover {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
right: 18px;
|
||||
width: max-content;
|
||||
padding: 10px;
|
||||
background: $white;
|
||||
border-radius: 5px 0 5px 5px;
|
||||
box-shadow: 0 0 6px $disable-color;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
right: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
content: "";
|
||||
border-top: 10px solid transparent;
|
||||
border-right: 0 solid transparent;
|
||||
border-bottom: 10px solid $white;
|
||||
border-left: 14px solid transparent;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: -22px;
|
||||
right: -1px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
content: "";
|
||||
border-top: 10px solid transparent;
|
||||
border-right: 0 solid transparent;
|
||||
border-bottom: 10px solid rgb(114 113 113 / 10%);
|
||||
border-left: 14px solid transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,242 @@
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { PREFIX } from '../../_constants'
|
||||
import NutRate from '../../rate/rate.vue'
|
||||
|
||||
defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default', // default,complex
|
||||
},
|
||||
info: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['handleClick'])
|
||||
|
||||
function handleClick() {
|
||||
emit('handleClick')
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
const componentName = `${PREFIX}-comment-header`
|
||||
|
||||
export default defineComponent ({
|
||||
name: componentName,
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view>
|
||||
<view v-if="info" class="nut-comment-header" @click="handleClick">
|
||||
<view class="nut-comment-header__user">
|
||||
<view class="nut-comment-header__user-avter">
|
||||
<image v-if="info.avatar" :src="info.avatar" />
|
||||
</view>
|
||||
|
||||
<view v-if="type === 'default'" :class="[`nut-comment-header__user-${type}`]">
|
||||
<view :class="[`nut-comment-header__user-${type}-name`]">
|
||||
<text>{{ info.nickName }}</text>
|
||||
<slot name="labels" />
|
||||
</view>
|
||||
|
||||
<view class="nut-comment-header__user-score">
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<NutRate
|
||||
v-model="info.score"
|
||||
size="12"
|
||||
spacing="5"
|
||||
readonly
|
||||
@change="handleClick"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else :class="[`nut-comment-header__user-${type}`]">
|
||||
<text :class="[`nut-comment-header__user-${type}-name`]">
|
||||
{{ info.nickName }}
|
||||
</text>
|
||||
<slot name="labels" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="info.time" class="nut-comment-header__time">
|
||||
{{ info.time }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="type === 'complex'" :class="[`nut-comment-header__${type}-score`]">
|
||||
<NutRate
|
||||
v-model="info.score"
|
||||
size="12"
|
||||
spacing="3"
|
||||
readonly
|
||||
/>
|
||||
<i :class="[`nut-comment-header__${type}-score-i`]" />
|
||||
<view :class="[`nut-comment-header__${type}-score-size`]">
|
||||
{{ info.size }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.nut-theme-dark {
|
||||
.nut-comment {
|
||||
&-header {
|
||||
&__user {
|
||||
&-name {
|
||||
color: $dark-color;
|
||||
}
|
||||
|
||||
&-default {
|
||||
&-name {
|
||||
color: $dark-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nut-comment {
|
||||
&-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&__user {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
|
||||
&-avter {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
|
||||
image {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&-name {
|
||||
/* stylelint-disable-next-line at-rule-no-unknown */
|
||||
@include oneline-ellipsis;
|
||||
|
||||
width: auto;
|
||||
max-width: 80px;
|
||||
margin-right: 5px;
|
||||
font-size: 12px;
|
||||
color: $comment-header-user-name-color;
|
||||
}
|
||||
|
||||
&-default {
|
||||
flex: 1;
|
||||
|
||||
&-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 3px;
|
||||
|
||||
/* stylelint-disable-next-line at-rule-no-unknown */
|
||||
@include oneline-ellipsis;
|
||||
|
||||
font-size: 12px;
|
||||
color: $comment-header-user-name-color;
|
||||
|
||||
> text {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-complex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $comment-header-user-name-color;
|
||||
|
||||
&-name {
|
||||
max-width: 80px;
|
||||
margin-right: 10px;
|
||||
|
||||
/* stylelint-disable-next-line at-rule-no-unknown */
|
||||
@include text-ellipsis;
|
||||
}
|
||||
|
||||
image {
|
||||
max-width: 50px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&-score {
|
||||
.nut-rate-item {
|
||||
display: block !important;
|
||||
line-height: 10px;
|
||||
|
||||
.nut-icon {
|
||||
line-height: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__time {
|
||||
width: 100px;
|
||||
font-size: 12px;
|
||||
color: $comment-header-time-color;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&__complex-score {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.nut-rate-item {
|
||||
display: block !important;
|
||||
line-height: 12px;
|
||||
|
||||
.nut-icon {
|
||||
line-height: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&-i {
|
||||
display: inline-block;
|
||||
width: 1px;
|
||||
height: 6px;
|
||||
margin: 0 8px 0 6px;
|
||||
font-style: inherit;
|
||||
background: $text-color;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
&-size {
|
||||
/* stylelint-disable-next-line at-rule-no-unknown */
|
||||
@include oneline-ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
&__labels--item {
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,228 @@
|
||||
<script setup lang="ts">
|
||||
import type { PropType } from 'vue'
|
||||
import { defineComponent, onMounted, ref, watch } from 'vue'
|
||||
import { PREFIX } from '../../_constants'
|
||||
import NutIcon from '../../icon/icon.vue'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: 'one', // one multi
|
||||
},
|
||||
videos: {
|
||||
type: Array as PropType<VideosType[]>,
|
||||
default: () => [],
|
||||
},
|
||||
images: {
|
||||
type: Array as PropType<ImagesType[]>,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['click', 'clickImages'])
|
||||
|
||||
interface VideosType {
|
||||
id: number | string
|
||||
mainUrl: string
|
||||
videoUrl: string
|
||||
}
|
||||
interface ImagesType {
|
||||
smallImgUrl: string
|
||||
bigImgUrl: string
|
||||
imgUrl: string
|
||||
}
|
||||
|
||||
const totalImages = ref<(VideosType | ImagesType)[]>([])
|
||||
|
||||
watch(
|
||||
() => [props.videos, props.images],
|
||||
(value) => {
|
||||
if (value[0].length > 0) {
|
||||
value[0].forEach((el: any) => {
|
||||
el.type = 'video'
|
||||
})
|
||||
}
|
||||
totalImages.value = (value[0] as any).concat(value[1])
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
if (props.videos.length > 0) {
|
||||
props.videos.forEach((el: any) => {
|
||||
el.type = 'video'
|
||||
})
|
||||
}
|
||||
totalImages.value = (props.videos as any).concat(props.images)
|
||||
})
|
||||
|
||||
function showImages(type: string, index: string | number) {
|
||||
const { videos, images } = props
|
||||
|
||||
const i = type === 'img' ? (index as number) - videos.length : index
|
||||
emit('clickImages', {
|
||||
type,
|
||||
index: i,
|
||||
value: type === 'img' ? images[i as number] : videos[i as number],
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
const componentName = `${PREFIX}-comment-images`
|
||||
|
||||
export default defineComponent({
|
||||
name: componentName,
|
||||
options: {
|
||||
virtualHost: true,
|
||||
addGlobalClass: true,
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view :class="`nut-comment-images nut-comment-images--${type}`">
|
||||
<!-- videos -->
|
||||
<view
|
||||
v-for="(itV, index) in videos"
|
||||
:key="itV.id"
|
||||
class="nut-comment-images__item nut-comment-images__item--video"
|
||||
@click="showImages('video', index)"
|
||||
>
|
||||
<image :src="itV.mainUrl" />
|
||||
<view class="nut-comment-images__play" />
|
||||
</view>
|
||||
<!-- images -->
|
||||
<template v-for="(itI, index) in images" :key="index">
|
||||
<view
|
||||
v-if="(type === 'multi' && videos.length + index < 9) || type !== 'multi'"
|
||||
class="nut-comment-images__item nut-comment-images__item--imgbox"
|
||||
@click="showImages('img', index + videos.length)"
|
||||
>
|
||||
<image :src="itI.smallImgUrl ? itI.smallImgUrl : itI.imgUrl" />
|
||||
|
||||
<view
|
||||
v-if="type === 'multi' && totalImages.length > 9 && videos.length + index > 7"
|
||||
class="nut-comment-images__mask"
|
||||
>
|
||||
<text>共 {{ totalImages.length }} 张</text>
|
||||
<NutIcon name="right" size="12px" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.nut-comment {
|
||||
&-images {
|
||||
display: flex;
|
||||
margin: 10px 0 12px;
|
||||
overflow: auto hidden;
|
||||
|
||||
&__item {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-right: 5px;
|
||||
overflow: hidden;
|
||||
border-radius: 6px;
|
||||
|
||||
image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
// &--imgbox {
|
||||
// // background: #f00;
|
||||
// }
|
||||
|
||||
&--video {
|
||||
// stylelint-disable-next-line rule-empty-line-before
|
||||
image {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
// height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 90px;
|
||||
font-size: 12px;
|
||||
line-height: 90px;
|
||||
color: rgb(255 255 255 / 100%);
|
||||
background: rgb(0 0 0 / 50%);
|
||||
}
|
||||
}
|
||||
|
||||
&-images--multi {
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin: 10px auto 15px;
|
||||
overflow: hidden;
|
||||
|
||||
.nut-comment-images__item {
|
||||
width: calc(34% - 8px);
|
||||
height: 90px;
|
||||
margin: 8px 8px 0 0;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.svg-demo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&:nth-child(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
display: block;
|
||||
width: 105px;
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
&-images__play {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: rgb(0 0 0 / 50%);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%);
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
left: 15px;
|
||||
display: block;
|
||||
content: "";
|
||||
border-top: 9px solid transparent;
|
||||
border-bottom: 9px solid transparent;
|
||||
border-left: 15px solid #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user