新增积分锁客页面,基础设置,商品设置,兑换记录

This commit is contained in:
gyq
2025-12-11 19:27:22 +08:00
parent ea5ce3caa1
commit 214026e859
15 changed files with 2188 additions and 78 deletions

View File

@@ -0,0 +1,142 @@
<!-- 优惠券图标 -->
<template>
<view class="container">
<view class="icon icon1" v-if="props.item[props.typeKey] == 1">
<view class="top">
<text class="i"></text>
<text class="num">{{ props.item.discountAmount }}</text>
</view>
<view class="intro">
<text class="t">{{ props.item.fullAmount }}可用</text>
</view>
</view>
<view class="icon icon2" v-if="props.item[props.typeKey] == 2">
<view class="top">
<text class="i">{{ props.item.discountNum }}</text>
<text class="num">商品兑换</text>
</view>
<view class="intro">
<text class="t">{{ props.item.fullAmount }}可用</text>
</view>
</view>
<view class="icon icon3" v-if="props.item[props.typeKey] == 3">
<view class="top">
<text class="num">{{ props.item.discountRate / 10 }}</text>
</view>
<view class="intro">
<text class="t">{{ props.item.fullAmount }}可用</text>
</view>
</view>
<view class="icon icon2" v-if="props.item[props.typeKey] == 4">
<view class="top">
<text class="i">第二件</text>
<text class="num">半价券</text>
</view>
</view>
<view class="icon icon2" v-if="props.item[props.typeKey] == 6">
<view class="top">
<text class="i">买一送</text>
<text class="num">一券</text>
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
item: {
type: Object,
default: {}
},
typeKey: {
type: String,
default: 'type'
}
});
</script>
<style scoped lang="scss">
$color: #ff1c1c;
.container {
width: 100%;
height: 100%;
.icon {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
&.icon1 {
.top {
.i {
color: $color;
font-size: 24upx;
font-weight: bold;
}
.num {
color: $color;
font-size: 72upx;
font-weight: bold;
}
}
}
&.icon2 {
.top {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.i {
color: $color;
font-size: 34upx;
font-weight: bold;
}
.num {
color: $color;
font-size: 34upx;
font-weight: bold;
}
}
}
&.icon3 {
.top {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.i {
color: $color;
font-size: 34upx;
font-weight: bold;
}
.num {
color: $color;
font-size: 52upx;
font-weight: bold;
}
}
}
.intro {
display: flex;
justify-content: center;
.t {
font-size: 22upx;
color: #999;
}
}
}
}
</style>

View File

@@ -0,0 +1,326 @@
<template>
<view>
<view class="list">
<view class="item" v-for="item in listData.list" :key="item.id">
<view class="top">
<text class="t">排序值{{ item.sort }}</text>
<view class="quantity" @click="showEdtorQuantityHandle(item)">
<text class="t">库存{{ item.quantity }}</text>
<u-icon name="edit-pen" color="#999"></u-icon>
</view>
</view>
<view class="goods-wrap">
<view class="left">
<view class="icon" v-if="includesString(item.goodsCategory, '其它商品')">
<image class="img" :src="item.goodsImageUrl" mode="aspectFill"></image>
</view>
<view class="icon border" v-if="includesString(item.goodsCategory, '优惠券')">
<couponIcon :item="item.couponInfo" typeKey="couponType" />
</view>
<view class="info-wrap">
<text class="name">{{ item.goodsName }}</text>
<text class="num">{{ item.requiredPoints }}积分 + {{ item.extraPrice || 0 }}</text>
</view>
</view>
<view class="status-wrap">
<u-switch v-model="item.status" :active-value="1" :inactive-value="0" @change="statusChange($event, item)"></u-switch>
<text class="t">
<template v-if="item.status == 0">上架</template>
<template v-if="item.status == 1">下架</template>
</text>
</view>
</view>
<view class="footer-wrap">
<view class="btn">
<u-button shape="circle" @click="delHandle(item)">删除</u-button>
</view>
<view class="btn">
<u-button type="primary" shape="circle" @click="toEditor(item)">编辑</u-button>
</view>
</view>
</view>
</view>
<u-loadmore :status="listData.status"></u-loadmore>
<u-popup :show="showEdtorQuantity" mode="center" :safeAreaInsetBottom="false" @close="showEdtorQuantity = false">
<view class="quantity-wrap">
<view class="title">
<text class="t">修改库存</text>
</view>
<view class="form-content">
<u-form :model="quantityItem" :rules="quantityFormRules">
<u-form-item label="数量">
<u-input v-model="quantityItem.quantity" placeholder="请输入数量" @change="quantityInput" clearable></u-input>
</u-form-item>
</u-form>
</view>
<view class="quantity-footer">
<view class="btn">
<u-button style="width: 100%" shape="circle" @click="showEdtorQuantity = false">取消</u-button>
</view>
<view class="btn">
<u-button type="primary" style="width: 100%" shape="circle" @click="submitQuntity">确认</u-button>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue';
import { onReachBottom } from '@dcloudio/uni-app';
import { pointsGoodsPage, pointsGoodsPost, pointsGoodsDel } from '@/http/api/market/point.js';
import { filterNumberInput, includesString } from '@/utils/index.js';
import couponIcon from './coupon-icon.vue';
const listData = reactive({
page: 1,
size: 10,
status: 'loading',
list: []
});
function reachBottom() {
if (listData.status != 'nomore') {
listData.page++;
pointsGoodsPageAjax();
}
}
// 积分:商品:列表
async function pointsGoodsPageAjax(page = listData.page) {
try {
const res = await pointsGoodsPage({
page: page,
size: listData.size
});
if (listData.page == 1) {
listData.list = res.records;
} else {
listData.list.push(...res.records);
}
if (res.pageNumber >= res.totalPage) {
listData.status = 'nomore';
}
} catch (error) {
console.log(error);
}
}
// 状态修改
function statusChange(e, item) {
pointsGoodsPostAjax(item);
}
// 积分:商品:新增/修改
async function pointsGoodsPostAjax(item) {
try {
await pointsGoodsPost(item);
pointsGoodsPageAjax();
} catch (error) {
console.log(error);
}
}
// 显示修改库存
const quantityItem = ref({});
const showEdtorQuantity = ref(false);
const quantityFormRules = ref({
quantity: [
{
required: true,
trigger: ['blur'],
message: '请输入',
validator: (rule, value, callback) => {
if (quantityItem.value.quantity < 0 || quantityItem.value.quantity === '') {
return false;
} else {
return true;
}
}
}
]
});
function quantityInput(e) {
setTimeout(() => {
quantityItem.value.quantity = filterNumberInput(e, 1);
}, 50);
}
function showEdtorQuantityHandle(item) {
quantityItem.value = { ...item };
showEdtorQuantity.value = true;
}
// 提交库存修改
async function submitQuntity() {
try {
uni.showLoading({
title: '保存中...',
mask: true
});
await pointsGoodsPost(quantityItem.value);
uni.showToast({
title: '保存成功',
icon: 'none'
});
pointsGoodsPageAjax();
showEdtorQuantity.value = false;
} catch (error) {
console.log(error);
}
uni.hideLoading();
}
// 删除
function delHandle(item) {
uni.showModal({
title: '注意',
content: `确认要删除${item.goodsName}商品吗?`,
success: async (res) => {
try {
if (res.confirm) {
uni.showLoading({
title: '删除中...',
mask: true
});
await pointsGoodsDel(item.id);
uni.showToast({
title: '已删除',
icon: 'none'
});
let index = listData.list.findIndex((val) => val.id == item.id);
listData.list.splice(index, 1);
}
} catch (error) {
console.log(error);
}
uni.hideLoading();
}
});
}
function toEditor(item) {
uni.navigateTo({
url: `/pageMarket/points/addProduct?id=${item.id}`
});
}
defineExpose({
reachBottom,
pointsGoodsPageAjax
});
onMounted(() => {
pointsGoodsPageAjax();
});
</script>
<style scoped lang="scss">
.list {
padding-bottom: 28upx;
.item {
border-radius: 16upx;
background-color: #fff;
padding: 28upx;
&:not(:first-child) {
margin-top: 28upx;
}
.top {
display: flex;
align-items: center;
gap: 44upx;
.t {
font-size: 24upx;
color: #666;
}
.quantity {
display: flex;
align-items: center;
gap: 4upx;
}
}
.goods-wrap {
display: flex;
padding: 28upx 0;
.left {
flex: 1;
display: flex;
align-items: center;
.icon {
$size: 180upx;
width: $size;
height: $size;
&.border {
border: 1px solid #ececec;
border-radius: 16upx;
padding: 16upx;
}
.img {
width: 100%;
height: 100%;
border-radius: 16upx;
}
}
.info-wrap {
display: flex;
flex-direction: column;
gap: 28upx;
padding-left: 20upx;
.name {
font-size: 28upx;
font-weight: bold;
color: #333;
}
}
}
.status-wrap {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4upx;
.t {
font-size: 24upx;
color: #666;
}
}
}
.footer-wrap {
display: flex;
justify-content: flex-end;
gap: 28upx;
.btn {
width: 140upx;
}
}
}
}
.quantity-wrap {
width: 80vw;
.title {
display: flex;
justify-content: center;
padding: 28upx;
.t {
font-size: 32upx;
font-weight: bold;
color: #333;
}
}
.form-content {
padding: 0 28upx;
}
.quantity-footer {
display: flex;
gap: 28upx;
padding: 28upx;
.btn {
flex: 1;
}
}
}
</style>

View File

@@ -0,0 +1,414 @@
<template>
<view class="container">
<view class="tab-wrap" :style="{ top: `${top}px` }">
<view class="item" :class="{ active: tabsActive == index }" v-for="(item, index) in tabs" :key="index" @click="changeTabHandle(index)">
<text class="t">{{ item.label }}</text>
</view>
</view>
<view class="list">
<view class="item" v-for="item in listData.list" :key="item.id">
<view class="top">
<text class="t">{{ item.orderNo }}</text>
<u-tag :type="statusFilter(item.status).type" plain plainFill>{{ item.status }}</u-tag>
</view>
<view class="row">
<text class="name">用户{{ item.nickName }} {{ item.phone }}</text>
</view>
<view class="goods-wrap">
<view class="left">
<view class="icon" v-if="includesString(item.goodsCategory, '其它商品')">
<image class="img" :src="item.goodsImageUrl" mode="aspectFill"></image>
</view>
<view class="icon border" v-if="includesString(item.goodsCategory, '优惠券')">
<couponIcon :item="item.couponInfo" typeKey="couponType" />
</view>
<view class="info-wrap">
<text class="name">{{ item.pointsGoodsName }}</text>
<text class="num">x{{ item.number }}</text>
</view>
</view>
<view class="status-wrap">
<text class="t">{{ item.spendPoints }}积分 + {{ item.extraPaymentAmount }}</text>
</view>
</view>
<view class="row">
<text class="t">下单时间{{ item.createTime }}</text>
</view>
<view class="row" v-if="item.checkoutTime">
<text class="t">核销时间{{ item.checkoutTime }}</text>
</view>
<view class="footer-wrap" v-if="includesString(item.status, '退款中') || includesString(item.status, '待核销')">
<view class="btn" v-if="includesString(item.status, '退款中')">
<u-button type="error" shape="circle" @click="refundCostHandle(item)">审核</u-button>
</view>
<view class="btn" v-if="includesString(item.status, '待核销')">
<u-button type="primary" shape="circle" @click="checkoutHandle(item)">核销</u-button>
</view>
</view>
</view>
</view>
<u-loadmore :status="listData.status"></u-loadmore>
<u-popup :show="showRefundPopup" :round="20" mode="bottom" closeable @close="showRefundPopup = false">
<view class="refund-popup-content">
<view class="refund-popup-title">
<text class="t">退款审核</text>
</view>
<view class="form">
<u-form :model="refundForm" label-width="70" label-position="left">
<u-form-item label="是否同意">
<u-radio-group v-model="refundForm.type">
<u-radio label="同意" :name="1" :customStyle="{ marginRight: '15px' }"></u-radio>
<u-radio label="驳回" :name="0"></u-radio>
</u-radio-group>
</u-form-item>
<u-form-item label="驳回原因" v-if="refundForm.type === 0">
<u-textarea type="textarea" v-model="refundForm.reason" placeholder="请输入驳回原因"></u-textarea>
</u-form-item>
</u-form>
</view>
<view class="dialog-footer">
<view class="btn">
<u-button @click="showRefundPopup = false" shape="circle" style="width: 100%">取消</u-button>
</view>
<div class="btn">
<u-button type="primary" shape="circle" @click="returnCostConfirmHandle" :loading="refundLoading" style="width: 100%">确认</u-button>
</div>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { goodsRecordPage, goodsRecordCkecout, goodsRecordAgreeRefund, goodsRecordRejectRefund } from '@/http/api/market/point.js';
import { includesString } from '@/utils/index.js';
import couponIcon from './coupon-icon.vue';
const props = defineProps({
top: {
type: Number,
default: 0
}
});
const tabsActive = ref(0);
const tabs = ref([
{
value: '',
label: '全部'
},
{
value: '待核销',
label: '待核销'
},
{
value: '已完成',
label: '已完成'
},
{
value: '退款中',
label: '售后'
}
]);
const statusList = ref([
{
label: '待支付',
type: 'info'
},
{
label: '待核销',
type: 'warning'
},
{
label: '已完成',
type: 'info'
},
{
label: '退款中',
type: 'error'
},
{
label: '已退款',
type: 'info'
}
]);
function statusFilter(status) {
const obj = statusList.value.find((item) => item.label == status);
if (obj) {
return obj;
} else {
return {
label: status,
type: 'info'
};
}
}
// 切换tab
function changeTabHandle(index) {
tabsActive.value = index;
listData.status = 'loading';
listData.page = 1;
listData.list = [];
goodsRecordPageAjax();
}
const listData = reactive({
page: 1,
size: 10,
status: 'loading',
list: []
});
function reachBottom() {
if (listData.status != 'nomore') {
listData.page++;
goodsRecordPageAjax();
}
}
// 确认核销
function checkoutHandle(item) {
uni.showModal({
title: '注意',
content: `确认要核销吗?`,
success: async (res) => {
try {
if (res.confirm) {
uni.showLoading({
title: '核销中...',
mask: true
});
await goodsRecordCkecout(item.couponCode);
goodsRecordPageAjax();
uni.showToast({
title: '已核销',
icon: 'none'
});
}
} catch (error) {
console.log(error);
}
uni.hideLoading();
}
});
}
const refundLoading = ref(false);
const showRefundPopup = ref(false);
const refundForm = ref({
type: 1,
recordId: '',
orderNo: '',
reason: ''
});
// 显示退款操作
function refundCostHandle(row) {
refundForm.value.recordId = row.id;
refundForm.value.orderNo = row.orderNo;
showRefundPopup.value = true;
}
// 退款操作
async function returnCostConfirmHandle() {
try {
refundLoading.value = true;
if (refundForm.value.type == 1) {
// 同意
await goodsRecordAgreeRefund(refundForm.value);
} else {
// 驳回
await goodsRecordRejectRefund(refundForm.value);
}
showRefundPopup.value = false;
uni.showToast({
title: '操作成功',
icon: 'none'
});
goodsRecordPageAjax();
} catch (error) {
console.log(error);
}
setTimeout(() => {
refundLoading.value = false;
}, 500);
}
// 积分:积分商品:兑换记录
async function goodsRecordPageAjax(page = listData.page) {
try {
const res = await goodsRecordPage({
page: page,
size: listData.size,
status: tabs.value[tabsActive.value].value
});
if (listData.page == 1) {
listData.list = res.records;
} else {
listData.list.push(...res.records);
}
if (res.pageNumber >= res.totalPage) {
listData.status = 'nomore';
}
} catch (error) {
console.log(error);
}
}
defineExpose({
reachBottom,
goodsRecordPageAjax
});
onMounted(() => {
goodsRecordPageAjax();
});
</script>
<style scoped lang="scss">
.container {
padding-top: 50px;
}
.tab-wrap {
$color: #318afe;
width: 100%;
height: 50px;
position: fixed;
left: 0;
background-color: #fff;
display: flex;
z-index: 999;
.item {
flex: 1;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid #fff;
.t {
font-size: 28upx;
color: #333;
}
&.active {
border-bottom-color: $color;
.t {
color: $color;
}
}
}
}
.list {
padding-bottom: 28upx;
.item {
background-color: #fff;
border-radius: 20upx;
padding: 28upx;
&:not(:first-child) {
margin-top: 28upx;
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
.t {
font-size: 28upx;
color: #999;
}
}
.row {
.name {
font-size: 28upx;
color: #333;
}
.t {
font-size: 24upx;
color: #999;
}
}
.goods-wrap {
display: flex;
padding: 28upx 0;
.left {
flex: 1;
display: flex;
align-items: center;
.icon {
$size: 180upx;
width: $size;
height: $size;
&.border {
border: 1px solid #ececec;
border-radius: 16upx;
padding: 16upx;
}
.img {
width: 100%;
height: 100%;
border-radius: 16upx;
}
}
.info-wrap {
display: flex;
flex-direction: column;
gap: 28upx;
padding-left: 20upx;
.name {
font-size: 28upx;
font-weight: bold;
color: #333;
}
}
}
.status-wrap {
display: flex;
align-items: center;
.t {
font-size: 32upx;
color: #333;
font-weight: bold;
}
}
}
.footer-wrap {
display: flex;
justify-content: flex-end;
gap: 28upx;
padding-top: 28upx;
.btn {
width: 180upx;
}
}
}
}
.refund-popup-content {
padding: 0 28upx;
.refund-popup-title {
padding: 28upx;
display: flex;
justify-content: center;
.t {
font-size: 32upx;
color: #333;
font-weight: bold;
}
}
.form {
padding: 28upx;
}
.dialog-footer {
display: flex;
gap: 28upx;
.btn {
flex: 1;
}
}
}
</style>

View File

@@ -0,0 +1,290 @@
<template>
<view class="form">
<u-form ref="formRef" :model="form" :rules="rules" label-width="200px" label-position="top">
<view class="card">
<u-form-item>
<view class="switch-wrap">
<view class="top">
<text class="t">开启积分</text>
<u-switch v-model="form.enableRewards" :active-value="1" :inactive-value="0"></u-switch>
</view>
<view class="info">
<text class="t">开启后所有用户可通过消费获得积分及可用积分抵扣支付</text>
</view>
</view>
</u-form-item>
</view>
<view class="card">
<u-form-item prop="consumeAmount">
<view class="switch-wrap">
<view class="top">
<text class="t">消费送积分</text>
</view>
<view class="info">
<text class="i">每消费</text>
<view class="ipt">
<u-input placeholder="请输入" :maxlength="8" v-model="form.consumeAmount" @change="consumeAmountInput">
<template #suffix>
<text></text>
</template>
</u-input>
</view>
<text class="i">获得1积分</text>
</view>
</view>
</u-form-item>
<u-form-item prop="minPaymentAmount">
<view class="switch-wrap">
<view class="top">
<text class="t">可抵扣门槛</text>
</view>
<view class="info">
<view class="ipt">
<u-input placeholder="请输入" :maxlength="8" v-model="form.minPaymentAmount" @change="minPaymentAmountInput">
<template #suffix>
<text></text>
</template>
</u-input>
</view>
</view>
</view>
</u-form-item>
<u-form-item prop="maxDeductionRatio">
<view class="switch-wrap">
<view class="top">
<text class="t">最高抵扣比例</text>
</view>
<view class="info">
<view class="ipt">
<u-input placeholder="请输入" :maxlength="8" v-model="form.maxDeductionRatio" @change="maxDeductionRatioInput">
<template #suffix>
<text>%</text>
</template>
</u-input>
</view>
</view>
</view>
</u-form-item>
<u-form-item prop="equivalentPoints">
<view class="switch-wrap">
<view class="top">
<text class="t">抵扣积分比例</text>
</view>
<view class="info">
<text class="i">1元等于</text>
<view class="ipt">
<u-input placeholder="请输入" :maxlength="8" v-model="form.equivalentPoints" @change="equivalentPointsInput">
<template #suffix>
<text>积分</text>
</template>
</u-input>
</view>
</view>
</view>
</u-form-item>
</view>
<view class="card">
<u-form-item>
<view class="switch-wrap">
<view class="top">
<text class="t">开启积分商城</text>
<u-switch v-model="form.enablePointsMall" :active-value="1" :inactive-value="0"></u-switch>
</view>
</view>
</u-form-item>
</view>
</u-form>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { filterNumberInput } from '@/utils/index.js';
import { pointsConfigPost, pointsConfigGet } from '@/http/api/market/point.js';
const formRef = ref(null);
const form = ref({
enableRewards: 0,
consumeAmount: '', // 每消费xx元赠送1积分
minPaymentAmount: '', // 下单实付抵扣门槛
maxDeductionRatio: 100, // 下单最高抵扣比例
equivalentPoints: '', // 下单抵扣积分比例 1元=?积分
enablePointsMall: 0 // 开启积分商城
});
const rules = ref({
consumeAmount: [
{
required: true,
trigger: ['blur'],
message: '请输入',
validator: (rule, value, callback) => {
if (form.value.consumeAmount < 0 || form.value.consumeAmount === '') {
return false;
} else {
return true;
}
}
}
],
minPaymentAmount: [
{
required: true,
trigger: ['blur'],
message: '请输入',
validator: (rule, value, callback) => {
if (form.value.minPaymentAmount < 0 || form.value.minPaymentAmount === '') {
return false;
} else {
return true;
}
}
}
],
maxDeductionRatio: [
{
required: true,
trigger: ['blur'],
message: '请输入',
validator: (rule, value, callback) => {
if (form.value.maxDeductionRatio < 0 || form.value.maxDeductionRatio === '') {
return false;
} else {
return true;
}
}
}
],
equivalentPoints: [
{
required: true,
trigger: ['blur'],
message: '请输入',
validator: (rule, value, callback) => {
if (form.value.equivalentPoints < 0 || form.value.equivalentPoints === '') {
return false;
} else {
return true;
}
}
}
]
});
function consumeAmountInput(e) {
setTimeout(() => {
form.value.consumeAmount = filterNumberInput(e);
}, 50);
}
function minPaymentAmountInput(e) {
setTimeout(() => {
form.value.minPaymentAmount = filterNumberInput(e);
}, 50);
}
function maxDeductionRatioInput(e) {
setTimeout(() => {
form.value.maxDeductionRatio = filterNumberInput(e, 1);
if (form.value.maxDeductionRatio > 100) {
form.value.maxDeductionRatio = 100;
}
}, 50);
}
function equivalentPointsInput(e) {
setTimeout(() => {
form.value.equivalentPoints = filterNumberInput(e, 1);
}, 50);
}
// 提交
function submitHandle() {
formRef.value
.validate()
.then(async () => {
try {
uni.showLoading({
title: '保存中...',
mask: true
});
await pointsConfigPost(form.value);
uni.showToast({
title: '保存成功',
icon: 'none'
});
} catch (error) {
console.log(error);
}
uni.hideLoading();
})
.catch(() => {});
}
// 获取配置
async function pointsConfigGetAjax() {
try {
uni.showLoading({
title: '加载中...',
mask: true
});
const res = await pointsConfigGet();
form.value = res;
} catch (error) {
console.log(error);
}
setTimeout(() => {
uni.hideLoading();
}, 300);
}
defineExpose({
submitHandle
});
onMounted(() => {
pointsConfigGetAjax();
});
</script>
<style scoped lang="scss">
.card {
background-color: #fff;
border-radius: 20px;
padding: 28upx;
&:not(:last-child) {
margin-bottom: 28upx;
}
}
.switch-wrap {
flex: 1;
width: 100%;
.top {
display: flex;
align-items: center;
justify-content: space-between;
.t {
font-size: 32upx;
color: #333;
font-weight: bold;
}
}
.info {
padding-top: 16upx;
display: flex;
align-items: center;
gap: 16upx;
.i {
font-size: 28upx;
color: #666;
}
.ipt {
flex: 1;
}
.t {
font-size: 24upx;
color: #666;
}
}
}
</style>