From 1625b684412694851576dc2f2812b4d20c577803 Mon Sep 17 00:00:00 2001 From: xuxueyang <xuxy@fengyuntec.com> Date: 星期二, 03 九月 2024 15:34:39 +0800 Subject: [PATCH] update 兑换券的(之后还有会员价格) --- sub_pages/customer/coupon/good-detail.vue | 179 ++++++++++++ sub_pages/customer/coupon/coupon-all.vue | 49 -- sub_pages/customer/coupon/coupon-self.vue | 13 common/global.scss | 1 pages.json | 20 + static/images/customer/coupon/icon-rule.png | 0 sub_pages/customer/coupon/good-all.vue | 355 +++++++++++++++++++++++++ static/images/customer/coupon/good-point-icon.png | 0 static/images/customer/coupon/icon-point.png | 0 /dev/null | 22 - sub_pages/customer/coupon/coupon.scss | 30 ++ static/images/customer/coupon/good-top-bg.png | 0 pages/order/order-detail.vue | 1 sub_pages/customer/coupon/good-self.vue | 160 +++++++++++ pages/user/supplier-user.vue | 2 15 files changed, 766 insertions(+), 66 deletions(-) diff --git a/common/global.scss b/common/global.scss index 0baa73e..2cddd3b 100644 --- a/common/global.scss +++ b/common/global.scss @@ -72,6 +72,7 @@ height: 100; height: 100%; z-index: -1; + background-size: 100% 100%; } .component-popup_input_all{ margin: 0 auto; diff --git a/pages.json b/pages.json index d3ba1cd..6cb6d79 100644 --- a/pages.json +++ b/pages.json @@ -447,9 +447,10 @@ } }, { - "path": "coupon/point-self", + "path": "coupon/good-self", "style": { - "navigationBarTitleText": "我的兑换券" + "navigationBarTitleText": "我的兑换券", + "enablePullDownRefresh": true } }, { @@ -457,6 +458,21 @@ "style": { "navigationBarTitleText": "积分明细" } + }, + { + "path": "coupon/good-all", + "style": { + "navigationBarTitleText": "积分兑换", + "navigationStyle": "custom", + "enablePullDownRefresh": false + } + }, + { + "path" : "coupon/good-detail", + "style" : + { + "navigationBarTitleText" : "详情" + } } // #endif ] diff --git a/pages/order/order-detail.vue b/pages/order/order-detail.vue index a7e0920..4ff01fd 100644 --- a/pages/order/order-detail.vue +++ b/pages/order/order-detail.vue @@ -223,6 +223,7 @@ id: this.id, } }) + this.$message.hideLoading() if (code === 0) { //微信接口 diff --git a/pages/user/supplier-user.vue b/pages/user/supplier-user.vue index f0c97da..bc63022 100644 --- a/pages/user/supplier-user.vue +++ b/pages/user/supplier-user.vue @@ -183,7 +183,7 @@ <view>优惠券</view> </view> - <view class="service-icons" @click="goto('/sub_pages/customer/coupon/point-self',true)"> + <view class="service-icons" @click="goto('/sub_pages/customer/coupon/good-self',true)"> <image src="../../static/images/customer/service/service-icon-9.png" class="t2 service-icon "> </image> <view>兑换券</view> diff --git a/static/images/customer/coupon/good-point-icon.png b/static/images/customer/coupon/good-point-icon.png new file mode 100644 index 0000000..9412986 --- /dev/null +++ b/static/images/customer/coupon/good-point-icon.png Binary files differ diff --git a/static/images/customer/coupon/good-top-bg.png b/static/images/customer/coupon/good-top-bg.png new file mode 100644 index 0000000..fdfb444 --- /dev/null +++ b/static/images/customer/coupon/good-top-bg.png Binary files differ diff --git a/static/images/customer/coupon/icon-point.png b/static/images/customer/coupon/icon-point.png new file mode 100644 index 0000000..460964a --- /dev/null +++ b/static/images/customer/coupon/icon-point.png Binary files differ diff --git a/static/images/customer/coupon/icon-rule.png b/static/images/customer/coupon/icon-rule.png new file mode 100644 index 0000000..c709112 --- /dev/null +++ b/static/images/customer/coupon/icon-rule.png Binary files differ diff --git a/sub_pages/customer/coupon/coupon-all.vue b/sub_pages/customer/coupon/coupon-all.vue index 0b09762..f5c6d16 100644 --- a/sub_pages/customer/coupon/coupon-all.vue +++ b/sub_pages/customer/coupon/coupon-all.vue @@ -1,18 +1,22 @@ <template> <view class="coupon-container"> <view class=""> + <no-data v-if="!list||list.length==0" style="width: 100%;"></no-data> + <view v-for="(item,index) of list" :key="index" class="coupont-item all"> <view class="flex container img100"> <view class="info-price"> - <view class="price1">¥7.70</view> - <view class="price2">满¥100可用</view> + <view class="price1"> + {{item.maxDiscountAmount?(`${item.maxDiscountAmount}折`):(`¥${item.couponDiscountValue}`)}} + </view> + <view class="price2">{{item.minOrderAmount?(`满¥${item.minOrderAmount}可用`):'无门槛'}}</view> </view> <view class="info flex1"> <view class="title"> - 七夕专属福利券 + {{item.couponName||'-'}} </view> <view class="time"> - 有效期至2024-07-26 09:58:30 + 领取后{{item.usageTimeNum||''}}{{item.usageTimeTypeName||''}}有效 </view> <view class="button" @click="getCoupon(item)"> 立即领取 @@ -50,9 +54,10 @@ const { code, data - } = await this.$http.request('post', '/api/v2/coupon/point/exchange', { + } = await this.$http.request('post', '/api/v2/coupon/app/receive', { data: { - couponId: item.id + couponId: item.id, + num: 1 } }) if (code == 0) { @@ -74,35 +79,5 @@ <style lang="scss" scoped> @import './coupon.scss'; - .coupon-container { - - .coupont-item.all { - margin-top: 20rpx; - - .container { - .info { - .time { - margin-top: 0rpx; - } - - .button { - width: 150rpx; - height: 46rpx; - // box-shadow: 0rpx 4rpx 16rpx 0rpx rgba(0,0,0,0.14); - border-radius: 24rpx; - border: 2rpx solid rgba(68, 119, 90, 1); - font-weight: 400; - font-size: 24rpx; - color: rgba(68, 119, 90, 1); - line-height: 46rpx; - text-align: center; - margin-top: 10rpx; - } - } - } - } - - - - } + .coupon-container {} </style> \ No newline at end of file diff --git a/sub_pages/customer/coupon/coupon-self.vue b/sub_pages/customer/coupon/coupon-self.vue index ab9131d..086df04 100644 --- a/sub_pages/customer/coupon/coupon-self.vue +++ b/sub_pages/customer/coupon/coupon-self.vue @@ -6,18 +6,22 @@ </top-tabs> </view> <view class=""> + <no-data v-if="!list||list.length==0" style="width: 100%;"></no-data> + <view v-for="(item,index) of list" :key="index" class="coupont-item" :class="[query.status]"> <view class="flex container img100"> <view class="info-price"> - <view class="price1">¥7.70</view> - <view class="price2">满¥100可用</view> + <view class="price1"> + {{item.maxDiscountAmount?(`${item.maxDiscountAmount}折`):(`¥${item.couponDiscountValue}`)}} + </view> + <view class="price2">{{item.minOrderAmount?(`满¥${item.minOrderAmount}可用`):'无门槛'}}</view> </view> <view class="info flex1"> <view class="title"> - 七夕专属福利券 + {{item.couponName||'-'}} </view> <view class="time"> - 有效期至2024-07-26 09:58:30 + 有效期至{{item.usageEndDate||'-'}} </view> </view> </view> @@ -70,6 +74,7 @@ methods: { changeTab(flg) { + this.flg = '' + flg this.query.status = this.tabs[flg].status this.listApi = '/api/v2/coupon/app' + `/mine/${this.query.status}/list` this.refreshList() diff --git a/sub_pages/customer/coupon/coupon.scss b/sub_pages/customer/coupon/coupon.scss index 0d195e8..09cf692 100644 --- a/sub_pages/customer/coupon/coupon.scss +++ b/sub_pages/customer/coupon/coupon.scss @@ -96,4 +96,34 @@ } + } + // 列表页面 + .coupont-item.all { + margin-top: 20rpx; + + .container { + .info { + .time { + margin-top: 0rpx; + } + + .button { + width: 150rpx; + height: 46rpx; + // box-shadow: 0rpx 4rpx 16rpx 0rpx rgba(0,0,0,0.14); + border-radius: 24rpx; + border: 2rpx solid rgba(68, 119, 90, 1); + font-weight: 400; + font-size: 24rpx; + color: rgba(68, 119, 90, 1); + line-height: 46rpx; + text-align: center; + margin-top: 10rpx; + } + } + } + } + // 兑换的页面,不需要tip + .coupont-item.exchange{ + height: 220rpx; } \ No newline at end of file diff --git a/sub_pages/customer/coupon/good-all.vue b/sub_pages/customer/coupon/good-all.vue new file mode 100644 index 0000000..24d6818 --- /dev/null +++ b/sub_pages/customer/coupon/good-all.vue @@ -0,0 +1,355 @@ +<template> + <view class="good-list-container"> + <view class="top-bg img100 relative" :style="{'padding-top':(StatusBar)+'px','line-height':CustomBar+'rpx' }"> + <image class="component-bg" src="../../../static/images/customer/coupon/good-top-bg.png" + mode="scaleToFill" /> + + <view class="title"> + <uni-icons class="icon" type="left" size="24"></uni-icons> + 积分兑换 + </view> + <view class="flex point-info"> + <view class="point-record m-r-a"> + <view class="text-center title">我的积分</view> + <view class="flex"> + <image src="../../../static/images/customer/coupon/icon-point.png" class="point-icon"> + </image> + 1552 + <uni-icons class="icon" type="right" size="32"></uni-icons> + </view> + </view> + <view class="m-l-a m-r-0 rule"> + <view class="flex w-fit m-l-a m-r-15"> + <view class="m-r-10">规则</view> + <image src="../../../static/images/customer/coupon/icon-rule.png" class="rule-icon"> + </image> + </view> + <image class="good-point-icon" src="../../../static/images/customer/coupon/good-point-icon.png" + mode="scaleToFill" /> + </view> + </view> + </view> + <view class="p10"> + <top-tabs :tabs="tabs" :flg="flg" @change="changeTab" type="coupon"> + + </top-tabs> + </view> + <!-- 商品 --> + <view v-if="flg==0"> + <view class="query-scores flex flex-wrap-normal p15"> + <view class="item" v-for="(item,index) of scores" :key="index" @click="changeScore(item)" + :class="[(!item.min||query.pointLower==item.min)&&(!item.max || query.pointUpper==item.max)?'active':'']"> + {{item.max?(item.min?`${item.min}~${item.max}`:`${item.max}以下`):`${item.min}以上`}} + </view> + </view> + <no-data v-if="!list||list.length==0" style="width: 100%;"></no-data> + + <view class="good-container p15 flex"> + <view v-for="(item,index) of list" :key="index" class="good-item" @click="toDetail(item)"> + <image class="cover" :src="item.cover" :lazy-load="true" mode="scaleToFill"> + + </image> + <view class="title"> + {{item.name}} + </view> + <view class="flex score-info"> + <view><span class="score">{{item.point||'-'}}</span>积分</view> + <view class="button m-l-a m-r-0" @click.stop="exchange('good',item)">兑换</view> + </view> + </view> + </view> + </view> + <!-- 优惠券 --> + <view v-if="flg==1" class="coupon-container"> + <no-data v-if="!list||list.length==0" style="width: 100%;"></no-data> + <view v-for="(item,index) of list" :key="index" class="coupont-item all exchange"> + <view class="flex container img100"> + <view class="info-price"> + <!-- 优惠券类型(COUPON_TYPE)满减和无门槛 --> + <view class="price1"> + {{item.maxDiscountAmount?(`${item.maxDiscountAmount}折`):(`¥${item.couponDiscountValue}`)}} + </view> + <view class="price2">{{item.minOrderAmount?(`满¥${item.minOrderAmount}可用`):'无门槛'}}</view> + </view> + <view class="info flex1"> + <view class="title"> + {{item.couponName||'-'}} + </view> + <view class="time"> + 领取后{{item.usageTimeNum||''}}{{item.usageTimeTypeName||''}}有效 + </view> + <view class="flex"> + <view class="t-red"> + {{item.point||'0'}}积分 + </view> + <view class="button m-l-a m-r-0" @click="exchange('coupon',item)"> + 兑换 + </view> + </view> + </view> + </view> + + </view> + </view> + + </view> +</template> + +<script> + export default { + methods: { + changeTab(flg) { + this.flg = '' + flg + this.listApi = this.tabs[flg].api + this.refreshList() + }, + async exchange(type, item) { + var api = '' + if (type == 'good') { + api = '/api/customer/point/goods/exchange' + } + if (type == 'coupon') { + api = '/api/v2/coupon/point/exchange' + } + await this.$message.confirm('确定兑换吗') + this.$message.showLoading() + const { + code, + data + } = await this.$http.request('post', api, { + data: { + couponId: item.id, + goodsId: item.id, //兼容2个 + } + }) + this.$message.hideLoading() + if (code == 0) { + this.$message.showToast('兑换成功') + } + }, + toDetail(item) { + uni.navigateTo({ + url: '/sub_pages/customer/coupon/good-detail?id=' + item.id + }) + }, + changeScore(item){ + this.query.pointLower = item.min || undefined + this.query.pointUpper = item.max || undefined + this.refreshList() + } + }, + data() { + return { + CustomBar: uni.getStorageSync('CustomBar'), + StatusBar: uni.getStorageSync('StatusBar'), + flg: 0, + + tabs: [{ + name: '商品', + api: '/api/customer/point/goods/list', + + }, + { + name: '优惠券', + api: '/api/v2/coupon/app/activy/list', + + }, + ], + query: { + pointLower: 1001, + pointUpper: 3000 + }, + scores: [{ + min: 0, + max: 1000 + }, + { + min: 1001, + max: 3000 + }, + { + min: 3001, + max: 5000 + }, + { + min: 5001, + max: 10000 + }, + { + min: 10001, + max: 0 + }, + ] + } + }, + onLoad() { + this.listApi = '/api/customer/point/goods/list' + }, + + onReachBottom() { + this.getMore() + }, + } +</script> + +<style lang="scss" scoped> + .good-list-container { + .good-container { + .good-item { + background: #FFFFFF; + border-radius: 12rpx; + width: 330rpx; + margin-bottom: 30rpx; + + .cover { + width: 330rpx; + height: 330rpx; + background-size: 100% 100%; + } + + .title { + padding-top: 18rpx; + padding-bottom: 18rpx; + font-weight: 600; + font-size: 32rpx; + color: #000000; + line-height: 44rpx; + text-align: center; + } + + .score-info { + + line-height: 50rpx; + font-weight: 400; + font-size: 24rpx; + color: #44775A; + padding-bottom: 28rpx; + + .score { + font-weight: 600; + font-size: 36rpx; + color: #44775A; + } + } + + .button { + width: 106rpx; + height: 46rpx; + border-radius: 24rpx; + border: 2rpx solid #44775A; + font-weight: 400; + font-size: 24rpx; + color: #44775A; + } + } + + .good-item:nth-child(2n+1) { + margin-left: 0rpx; + margin-right: auto; + } + + .good-item:nth-child(2n) { + margin-right: 0rpx; + margin-left: auto; + } + } + + .query-scores { + overflow-x: scroll; + width: max-content; + .item { + padding-left: 16rpx; + padding-right: 16rpx; + text-align: center; + font-weight: 400; + font-size: 28rpx; + color: #333333; + line-height: 50rpx; + height: 50rpx; + border-radius: 26rpx; + // width: fit-content; + + } + + .item.active { + background: #E1F0E7; + font-weight: 600; + color: #1A8B4C; + } + } + + .top-bg { + padding: 32rpx; + padding-top: 40rpx; + height: 320rpx; + max-height: 320rpx; + + .point-info { + + .point-record { + // margin-left: 40rpx; + font-weight: 600; + font-size: 60rpx; + color: #44775A; + line-height: 84rpx; + + .title { + font-weight: 400; + font-size: 32rpx; + color: #000000; + line-height: 44rpx; + margin-top: 40rpx; + margin-bottom: 20rpx; + } + + .point-icon { + width: 42rpx; + height: 42rpx; + margin-top: 20rpx; + margin-right: 10rpx; + display: inline-block; + vertical-align: middle; + } + } + + .rule { + font-weight: 400; + font-size: 24rpx; + color: #44775A; + line-height: 30rpx; + + .good-point-icon { + width: 192rpx; + height: 162rpx; + margin-right: 120rpx; + margin-top: 10rpx; + } + + .rule-icon { + width: 30rpx; + height: 30rpx; + + display: inline-block; + vertical-align: middle; + } + } + + + } + + .title { + text-align: center; + font-weight: 600; + font-size: 32rpx; + position: relative; + + .icon { + position: absolute; + left: 20rpx; + z-index: 1; + } + } + + } + } +</style> \ No newline at end of file diff --git a/sub_pages/customer/coupon/good-detail.vue b/sub_pages/customer/coupon/good-detail.vue new file mode 100644 index 0000000..47fb628 --- /dev/null +++ b/sub_pages/customer/coupon/good-detail.vue @@ -0,0 +1,179 @@ +<template> + <view class="travel-detail"> + <view v-if="dto.id"> + <!-- 标题、价格、时间、地点 --> + <view class="infos"> + <view class="name">{{dto.name||dto.title||'暂无标题'}}</view> + <view class="flex score-info"> + <view><span class="score">{{dto.point||'-'}}</span>积分</view> + <view class="m-l-a m-r-0">库存:{{dto.stock||'0'}}</view> + </view> + </view> + <view style="background: #F5F5F5;height: 24rpx;"> + + </view> + + <view class="bg-white p10"> + <image :src="dto.cover" v-if="dto.cover" mode="aspectFit" class="m-t-8" + style="display: block;margin: 0 auto;" @click="previewImg(dto.cover)"></image> + + </view> + <uni-swiper-dot class="uni-swiper-dot-box" :mode="'dot'" field="content" + v-if="dto.pictureList&&dto.pictureList.length>0"> + <swiper class="swiper-box" :interval="10000" :circular="true" :current="0" :autoplay="true"> + <swiper-item v-for="(url, index) in dto.pictureList" :key="index"> + <view class="swiper-item" :class="'swiper-item' + index"> + <image class="home-banner-image" mode="scaleToFill" @click="previewImg(url)" :src="url"> + </image> + </view> + </swiper-item> + </swiper> + </uni-swiper-dot> + + <view style="background: #F5F5F5;height: 24rpx;"> + + </view> + + <view class="info-desc"> + <view class="title">商品描述</view> + <view v-html="dto.description||'暂无'" class="rich" style="overflow: scroll;"> + + </view> + </view> + + </view> + </view> +</template> + +<script> + export default { + data() { + return { + dto: { + + }, + id: '' + }; + }, + async onLoad(options) { + this.id = options.id || '' + await this.init() + + }, + async onPullDownRefresh() { + await this.init() + uni.stopPullDownRefresh() + }, + methods: { + async init() { + this.$message.showLoading() + const { + data + } = await this.$http.request('get', '/api/pub/announcement/page/view?id=' + this.id, { + + }) + this.$message.hideLoading() + this.dto = { + ...data + } + }, + } + } +</script> + +<style lang="scss" scoped> + .travel-detail { + + .info-desc { + padding: 24rpx 30rpx; + background: #fff; + + .title { + margin-bottom: 20rpx; + font-weight: 600; + font-size: 32rpx; + color: #000000; + } + + /deep/ img { + max-width: 600rpx; + + } + } + + + + .infos { + padding: 24rpx 30rpx; + background: #fff; + + .score-info { + + line-height: 50rpx; + font-weight: 400; + font-size: 24rpx; + color: #44775A; + padding-bottom: 28rpx; + + .score { + font-weight: 600; + font-size: 36rpx; + color: #44775A; + } + } + + + .name { + font-weight: 600; + font-size: 40rpx; + color: #000000; + } + + + .price { + font-weight: 600; + line-height: 72rpx; + font-size: 50rpx; + color: #000000; + + .dot { + font-size: 40rpx; + line-height: 56rpx; + } + } + + .status { + width: 132rpx; + height: 50rpx; + border-radius: 26rpx; + border: 2rpx solid #999999; + color: #999999; + line-height: 50rpx; + font-size: 24rpx; + + text-align: center; + margin-left: 16rpx; + } + + .status.A, + .status.J { + border: 2rpx solid #04BA97; + color: #04BA97; + } + + .icon-loc { + width: 24rpx; + height: 30rpx; + background-size: 100% 100%; + + } + + .icon-clock { + width: 24rpx; + height: 26rpx; + background-size: 100% 100%; + + } + } + } +</style> \ No newline at end of file diff --git a/sub_pages/customer/coupon/good-self.vue b/sub_pages/customer/coupon/good-self.vue new file mode 100644 index 0000000..2c981b9 --- /dev/null +++ b/sub_pages/customer/coupon/good-self.vue @@ -0,0 +1,160 @@ +<template> + <view class="coupon-container"> + <view class="p10"> + <top-tabs :tabs="tabs" :flg="flg" @change="changeTab" type="coupon"> + + </top-tabs> + </view> + <view class=""> + <no-data v-if="!list||list.length==0" style="width: 100%;"></no-data> + + <view v-for="(item,index) of list" :key="index" class="coupont-item" :class="[query.status]"> + <view class="flex container img100"> + <view class="info-price"> + <image :lazy-load="true" :src="item.cover" class="cover" mode="scaleToFill"></image> + </view> + <view class="info flex1"> + <view class="title"> + {{item.name||''}} + </view> + <view class="time word-e"> + {{item.description||''}} + </view> + <view class="button" @click="getPointGood(item)"> + 查看详情 + </view> + </view> + </view> + <view class="tip"> + <span class="t-red">*</span>此券每人限领1张。仅限用于花满芜鲜花交易平台鲜切花花款满额使用,不可与其他优惠同享、不可叠加使用 + </view> + </view> + </view> + <view style="min-height: 130rpx;"></view> + <view class="bottom-button" @click="toGoodAll">前往兑换</view> + </view> +</template> + +<script> + export default { + data() { + return { + flg: 0, + + tabs: [{ + name: '未使用', + status: 'A', + // unused + }, + { + name: '已使用', + status: 'U', + + // used + }, + { + name: '已过期', + status: 'E', + + // expired + }, + ], + query: { + status: 'A' + }, + list: [] + } + }, + async onLoad() { + this.listApi = '/api/customer/point/goods/exchange/list' + + this.getList() + }, + + methods: { + changeTab(flg) { + this.flg = '' + flg + this.query.status = this.tabs[flg].status + this.refreshList() + }, + getPointGood(item) { + uni.navigateTo({ + url: `/sub_pages/customer/coupon/good-detail?id=${item.id}` + }) + }, + toGoodAll() { + uni.navigateTo({ + url: `/sub_pages/customer/coupon/good-all` + }) + } + }, + // async onShow() { + // if (this.sign['coupon']) { + // this.$store.dispatch('sign_clear', 'coupon'); + // this.refreshList() + // } + // }, + async onPullDownRefresh() { + await this.refreshList() + uni.stopPullDownRefresh() + + }, + } +</script> + +<style lang="scss" scoped> + @import './coupon.scss'; + + .coupon-container { + .coupont-item { + .container { + background-image: unset; + + .info-price { + .cover { + width: 150rpx; + height: 150rpx; + } + } + + .info { + .time { + margin-top: 0rpx; + } + + .button { + width: 150rpx; + height: 46rpx; + // box-shadow: 0rpx 4rpx 16rpx 0rpx rgba(0,0,0,0.14); + border-radius: 24rpx; + border: 2rpx solid rgba(68, 119, 90, 1); + font-weight: 400; + font-size: 24rpx; + color: rgba(68, 119, 90, 1); + line-height: 46rpx; + text-align: center; + margin-top: 10rpx; + } + } + } + } + + + + .bottom-button { + width: 690rpx; + height: 90rpx; + border-radius: 46rpx; + border: 2rpx solid #20613D; + position: fixed; + bottom: 30rpx; + left: 50%; + transform: translateX(-50%); + font-weight: 400; + font-size: 32rpx; + color: #20613D; + text-align: center; + line-height: 90rpx; + } + } +</style> \ No newline at end of file diff --git a/sub_pages/customer/coupon/point-self.vue b/sub_pages/customer/coupon/point-self.vue deleted file mode 100644 index 8183fd0..0000000 --- a/sub_pages/customer/coupon/point-self.vue +++ /dev/null @@ -1,22 +0,0 @@ -<template> - <view> - - </view> -</template> - -<script> - export default { - data() { - return { - - } - }, - methods: { - - } - } -</script> - -<style> - -</style> -- Gitblit v1.9.3