Commit 5e3f6d21 by keith

update code

parent b6252c89
......@@ -59,8 +59,8 @@ func (c *HomeController) Statistical() {
}
// TodayActionStatistical today Statistical
func (c *HomeController) TodayActionStatistical() {
// GetFlowStatistical flow Statistical
func (c *HomeController) GetFlowStatistical() {
// request body
statisticalRequest := StatisticalRequest{}
......@@ -78,7 +78,7 @@ func (c *HomeController) TodayActionStatistical() {
}
}
statisticalData, err := c.StatisticalRepository.GetTodayActionStatistical(statisticalRequest.DateStart, statisticalRequest.DateEnd)
statisticalData, err := c.StatisticalRepository.GetFlowStatistical(statisticalRequest.DateStart, statisticalRequest.DateEnd)
if err != nil {
c.JSON(configs.ResponseFail, err.Error(), err.Error())
}
......
......@@ -771,7 +771,6 @@ func (c *PublicController) GetWorkOrder() {
// get user
user := c.GetUserInfo()
print(&user)
if user == nil {
// GetAdminAuthInfo
auth := c.GetAdminAuthInfo()
......@@ -806,6 +805,10 @@ func (c *PublicController) DeleteWorkOrder() {
if auth == nil {
c.JSON(configs.ResponseFail, "fail!", nil)
}
admin := services.GetAdminRepositoryInstance().GetAdmin(auth.UID)
if admin.Root == 0 {
c.JSON(configs.ResponseFail, "无权限删除!", nil)
}
}
// wid
......
......@@ -136,7 +136,7 @@ func (c *WorkOrderController) GetWorkType() {
// GetWorkTypes get work order types
func (c *WorkOrderController) GetWorkTypes() {
workOrderTypes := c.WorkOrderTypeRepository.GetWorkOrderTypes()
workOrderTypes := c.WorkOrderTypeRepository.GetWorkOrderTypesAndCountWorkorder()
c.JSON(configs.ResponseSucess, "查询成功!", workOrderTypes)
}
......
package models
// WorkOrderTypeDto model
type WorkOrderTypeDto struct {
ID int64 `orm:"auto;pk;type(bigint);column(id)" json:"id"` // ID
Title string `orm:"unique;type(varchar);null;column(title)" json:"title"` // 类型名称
Count int64 `orm:"type(bigint);column(count)" json:"count"` // 类型名称
CreateAt int64 `orm:"type(bigint);column(create_at)" json:"create_at"` // 提交时间
}
......@@ -61,7 +61,7 @@ func routers(prefix string) *beego.Namespace {
beego.NSNamespace("/home",
beego.NSBefore(filters.FilterToken),
beego.NSRouter("/statistical", &controllers.HomeController{}, "post:Statistical"),
beego.NSRouter("/today_statistical", &controllers.HomeController{}, "post:TodayActionStatistical"),
beego.NSRouter("/flow_statistical", &controllers.HomeController{}, "post:GetFlowStatistical"),
),
// message
......
......@@ -176,7 +176,7 @@ func (r *KnowledgeBaseRepository) Delete(id int64) (int64, error) {
// GetKnowledgeBasePlatformsTotal get Group count
func (r *KnowledgeBaseRepository) GetKnowledgeBasePlatformsTotal() []orm.Params {
var maps []orm.Params
_, err := r.o.Raw("select P.id,p.title,IFNULL(k.count,0) as count FROM platform p LEFT JOIN (SELECT platform,COUNT(*) AS count FROM `knowledge_base` GROUP BY platform) k ON k.platform = p.id").Values(&maps)
_, err := r.o.Raw("SELECT P.id,p.title,IFNULL(k.count,0) as count FROM platform p LEFT JOIN (SELECT platform,COUNT(*) AS count FROM `knowledge_base` GROUP BY platform) k ON k.platform = p.id").Values(&maps)
if err != nil {
logs.Warn("GetKnowledgeBasePlatformsTotal get Group count------------", err)
return []orm.Params{}
......
......@@ -14,7 +14,7 @@ import (
type StatisticalRepositoryInterface interface {
Add(servicesStatistical *models.ServicesStatistical) (int64, error)
GetStatisticals(startDate string, endDate string) (map[string]interface{}, error)
GetTodayActionStatistical(startDate string, endDate string) ([]orm.Params, error)
GetFlowStatistical(startDate string, endDate string) ([]orm.Params, error)
GetCustomerServiceList(request models.ServicesStatisticalPaginationDto) models.ServicesStatisticalPaginationDto
CheckIsReplyAndSetReply(uid int64, aid int64, platform int64)
}
......@@ -70,7 +70,7 @@ func (r *StatisticalRepository) GetCustomerServiceList(request models.ServicesSt
addSQL1 = " GROUP BY `user_account` "
}
if counter, err := r.o.Raw("SELECT s.id, s.user_account, s.service_account,s.create_at,s.is_reception, s.transfer_account,s.platform,u.nickname FROM services_statistical AS s INNER JOIN (SELECT * FROM `user` ) AS u ON s.user_account = u.id AND s.service_account = ? AND s.create_at > ? AND s.create_at < ? AND is_reception IN("+ INReception +") "+addSQL1+" ORDER BY s.create_at DESC LIMIT ?,?", request.Cid, startDate.Unix(), endDate.Unix(), (request.PageOn-1)*request.PageSize, request.PageSize).Values(&params); counter <= 0 {
if counter, err := r.o.Raw("SELECT s.id, s.user_account, s.service_account,s.create_at,s.is_reception, s.transfer_account,s.platform,u.nickname FROM services_statistical AS s INNER JOIN (SELECT * FROM `user` ) AS u ON s.user_account = u.id AND s.service_account = ? AND s.create_at > ? AND s.create_at < ? AND is_reception IN("+INReception+") "+addSQL1+" ORDER BY s.create_at DESC LIMIT ?,?", request.Cid, startDate.Unix(), endDate.Unix(), (request.PageOn-1)*request.PageSize, request.PageSize).Values(&params); counter <= 0 {
logs.Warn("GetCustomerServiceList get Customer Service List2------------", err)
request.List = []string{}
return request
......@@ -144,8 +144,8 @@ func (r *StatisticalRepository) GetStatisticals(startDate string, endDate string
return countsArr, nil
}
// GetTodayActionStatistical get Today Action Statistical
func (r *StatisticalRepository) GetTodayActionStatistical(startDate string, endDate string) ([]orm.Params, error) {
// GetFlowStatistical get Today Action Statistical
func (r *StatisticalRepository) GetFlowStatistical(startDate string, endDate string) ([]orm.Params, error) {
// transform date
layoutDate := "2006-01-02 15:04:05"
loc, _ := time.LoadLocation("Local")
......@@ -157,7 +157,7 @@ func (r *StatisticalRepository) GetTodayActionStatistical(startDate string, endD
var statisticalData []orm.Params
_, err := r.o.Raw("SELECT p.id platform,p.title, IFNULL(u.count,0) AS `count` FROM platform as p LEFT JOIN (SELECT platform,COUNT(*) AS count FROM `user` WHERE last_activity BETWEEN ? AND ? GROUP BY platform) u ON p.id = u.platform", dateStart.Unix(), dateEnd.Unix()).Values(&statisticalData)
if err != nil {
logs.Warn("GetTodayActionStatistical get Today Action Statistical------------", err)
logs.Warn("GetFlowStatistical get Today Action Statistical------------", err)
return nil, err
}
return statisticalData, nil
......
......@@ -80,7 +80,7 @@ func (r *WorkOrderRepository) GetWorkOrders(request models.WorkOrderPaginationDt
}
tidSQL := ""
if request.Tid != 0 {
tidSQL = " ADN `t_i_d` = " + strconv.FormatInt(request.Tid, 10) + " "
tidSQL = " AND `t_i_d` = " + strconv.FormatInt(request.Tid, 10) + " "
}
if request.PageSize == 0 {
request.PageSize = 10
......
......@@ -13,6 +13,7 @@ import (
type WorkOrderTypeRepositoryInterface interface {
GetWorkOrderType(id int64) (models.WorkOrderType, error)
GetWorkOrderTypes() []models.WorkOrderType
GetWorkOrderTypesAndCountWorkorder() []models.WorkOrderTypeDto
Update(id int64, params orm.Params) (int64, error)
Delete(id int64) (int64, error)
Add(data models.WorkOrderType) (bool, int64, error)
......@@ -71,6 +72,17 @@ func (r *WorkOrderTypeRepository) GetWorkOrderTypes() []models.WorkOrderType {
return workOrderTypes
}
// GetWorkOrderTypesAndCountWorkorder get all
func (r *WorkOrderTypeRepository) GetWorkOrderTypesAndCountWorkorder() []models.WorkOrderTypeDto {
var workOrderTypes []models.WorkOrderTypeDto
_, err := r.o.Raw("SELECT t.*,IFNULL(w.count,0) as `count` FROM work_order_type t LEFT JOIN (SELECT t_i_d,COUNT(*) AS `count` FROM `work_order` WHERE `delete` = 0 GROUP BY `t_i_d`) w ON t.id = w.t_i_d").QueryRows(&workOrderTypes)
if err != nil {
logs.Warn("GetWorkOrderTypes get all------------", err)
return []models.WorkOrderTypeDto{}
}
return workOrderTypes
}
// Update WorkOrderType Info
func (r *WorkOrderTypeRepository) Update(id int64, params orm.Params) (int64, error) {
var res models.WorkOrderType
......
......@@ -48,7 +48,7 @@
</el-col>
</el-row>
<div>
<div class="mini-im-home-title" style="padding-bottom: 10px;">各渠道<span style="color: #f44336;">当天独立用户</span>访问量</div>
<div class="mini-im-home-title" style="padding-bottom: 10px; text-align: left;">各渠道<span style="color: #f44336">{{optionsDate[selectDateValue].label}}独立用户</span>访问量</div>
<el-table
:data="todayStatisticalTableData"
style="width: 100%">
......@@ -66,7 +66,7 @@
prop="count"
align="center"
width="180"
label="当天访问人次">
label="访问人次">
</el-table-column>
<el-table-column
label="">
......@@ -129,7 +129,7 @@ export default {
created(){
this.selectDate = this.getDate(2)
this.getStatistical()
this.getTodayStatistical()
this.getFlowStatistical()
this.getOnlines()
},
computed:{
......@@ -186,11 +186,11 @@ export default {
this.$message.error(error.response.data.message)
});
},
// 获取今天访问数据
getTodayStatistical(){
axios.post('/home/today_statistical', {
"date_start": moment(new Date()).format("YYYY-MM-DD"),
"date_end": moment(new Date()).format("YYYY-MM-DD")
// 获取访问数据
getFlowStatistical(){
axios.post('/home/flow_statistical', {
"date_start": moment(this.selectDate[0]).format("YYYY-MM-DD"),
"date_end": moment(this.selectDate[1]).format("YYYY-MM-DD")
})
.then(response => {
this.todayStatisticalTableData = response.data.data
......@@ -239,6 +239,7 @@ export default {
// 时间变更
changeDate(){
this.getStatistical()
this.getFlowStatistical()
},
// 获取在线用户数
getOnlines(){
......
......@@ -11,8 +11,8 @@
:class="{'el-button--primary': item.id + '' == tableData.platform + ''}"
@click="onTogglePlatform(item.id)"
:key="item.id"
size="mini"
>{{item.title}} ({{item.count}})</el-button>
size="small"
>{{item.title}} ( {{item.count}} )</el-button>
</template>
</el-button-group>
<el-col :span="5">
......
......@@ -5,19 +5,44 @@
<span>
<i class="el-icon-tickets"></i>
<span slot="title">工单管理</span>
<span style="font-size:15px;margin-left: 30px;color:#e7a646">当前有
<strong style="color: #f56c6c">5</strong>
条待处理, 和<strong style="color: #f56c6c"> 8</strong>
条待回复工单</span>
</span>
<el-button size="mini">设置</el-button>
<div>
<el-button-group>
<el-radio size="small" v-model="workStatus" label="-1" border>全部</el-radio>
<el-radio size="small" v-model="workStatus" label="0" border>待处理</el-radio>
<el-radio size="small" v-model="workStatus" label="2" border>待回复</el-radio>
<el-radio size="small" v-model="workStatus" label="1" border>已回复</el-radio>
<el-radio size="small" v-model="workStatus" label="3" border>已关闭</el-radio>
</el-button-group>
</div>
<div>
<el-button size="mini">回收站 ( 52654 )</el-button>
<el-button size="mini">分类设置</el-button>
</div>
</div>
<el-divider />
<div class="container-box">
<div class="menu">
<el-tabs @tab-click="tabsChange" tab-position="left" style="width:200px;height: 80vh;">
<template size="small" v-for="item in workorderTypes" border>
<el-tab-pane :key="item.id" :label="item.title + '('+item.count+')'"></el-tab-pane>
</template>
</el-tabs>
</div>
<div class="table-content">
<el-table :data="tableData.list" style="width: 100%" v-loading="loading">
<el-table-column type="index" :index="indexMethod" width="60" label="#序号"></el-table-column>
<el-table-column prop="title" label="工单标题"></el-table-column>
<el-table-column prop="status" label="当前状态">
<template slot-scope="scope">
<el-tag type="warning" v-if="scope.row.status == 0">处理</el-tag>
<el-tag type="warning" v-if="scope.row.status == 1">回复</el-tag>
<el-tag type="success" v-if="scope.row.status == 2">回复</el-tag>
<el-tag type="info" v-if="scope.row.status == 3">已结束</el-tag>
<el-tag type="warning" v-if="scope.row.status == 0">等待客服处理</el-tag>
<el-tag type="warning" v-if="scope.row.status == 2">等待客服回复</el-tag>
<el-tag type="success" v-if="scope.row.status == 1">已有客服回复</el-tag>
<el-tag type="info" v-if="scope.row.status == 3"> 工单已结束 </el-tag>
</template>
</el-table-column>
<el-table-column prop="u_nickname" label="用户(发布者)"></el-table-column>
......@@ -47,6 +72,8 @@
:total="tableData.total"
></el-pagination>
</el-row>
</div>
</div>
<WorkOrderView :prop="showWorkOrder" v-model="isShowWorkOrderView" />
</div>
</template>
......@@ -63,6 +90,7 @@ export default {
loading: true,
isShowWorkOrderView: false,
showWorkOrder: {},
workStatus: "-1",
tableData: {
list: [],
page_on: 1,
......@@ -70,25 +98,38 @@ export default {
total: 0,
status: -1,
tid: 0
},
workorderTypes:[
{
"id": 0,
"count": 0,
"title": "全部工单"
}
],
};
},
created() {
setTimeout(() => {
this.getWorkorderList();
}, 500);
this.getWorkorderTypes()
},
methods: {
onShow(item){
this.showWorkOrder = item
this.isShowWorkOrderView = true
},
tabsChange(tab){
this.changeType(this.workorderTypes[parseInt(tab.index)].id)
},
// 行号
indexMethod(index) {
return (
(this.tableData.page_on - 1) * this.tableData.page_size + index + 1
);
},
changeType(tid){
this.tableData.tid = tid;
this.getWorkorderList(1);
},
// 获取数据
getWorkorderList(index) {
if (index) this.tableData.page_on = index;
......@@ -104,6 +145,20 @@ export default {
this.$message.error(error.response.data.message);
});
},
// 获取类型数据
getWorkorderTypes() {
axios
.get("/workorder/types")
.then(response => {
this.workorderTypes = this.workorderTypes.concat(response.data.data);
for(var i=0; i<response.data.data.length; i++){
this.workorderTypes[0].count += response.data.data[i].count
}
})
.catch(error => {
this.$message.error(error.response.data.message);
});
},
// 改变每页条数
handleSizeChange(val) {
this.tableData.page_size = val;
......@@ -114,6 +169,17 @@ export default {
this.tableData.page_on = val;
this.getWorkorderList();
}
},
watch: {
isShowWorkOrderView(show){
if(!show){
this.getWorkorderList();
}
},
workStatus(status){
this.tableData.status = parseInt(status)
this.getWorkorderList();
}
}
};
</script>
......@@ -130,5 +196,15 @@ export default {
margin-right: 5px;
}
}
.container-box{
display flex
.menu{
flex-shrink: 0;
width 180px;
}
.table-content{
flex-grow 1
}
}
</style>
......@@ -3,10 +3,24 @@
<div class="workorder-view" :class="{'is-show-aside': !isShowAside}" v-show="value">
<div class="mask" @dblclick="close"></div>
<transition name="el-zoom-in-bottom">
<div class="content-box" v-show="value">
<div class="content-box" :class="{'padding-bottom30': showData.status == 3}" v-show="value">
<div class="title">
<i class="el-icon-tickets"></i> 工单详细
</div>
<div class="buttons">
<el-button
size="mini"
@click="closeWorkorder"
v-if="showData.status == 1 || showData.status == 2"
type="warning"
>关闭工单</el-button>
<el-button
size="mini"
@click="delWorkorder"
v-if="showData.status == 3 && adminInfo.root == 1"
type="danger"
>删除工单</el-button>
</div>
<span class="close" @click="close">
<i class="el-icon-close"></i>
</span>
......@@ -31,10 +45,10 @@
<div class="form-line">
<span class="lable">状态:</span>
<div class="con">
<span style="color:#e6a23c;" v-if="showData.status == 0">处理</span>
<span style="color:#e6a23c;" v-if="showData.status == 1">回复</span>
<span style="color:#67c23a;" v-if="showData.status == 2">回复</span>
<span style="color:#909399;" v-if="showData.status == 3">已结束</span>
<span style="color:#e6a23c;" v-if="showData.status == 0">等待客服处理</span>
<span style="color:#e6a23c;" v-if="showData.status == 2">等待客服回复</span>
<span style="color:#67c23a;" v-if="showData.status == 1">已有客服回复</span>
<span style="color:#909399;" v-if="showData.status == 3">工单已结束</span>
</div>
</div>
<div class="form-line">
......@@ -46,7 +60,7 @@
<div class="no-data" v-if="comments.length <= 0 && !isShowGetCommentsLoading">暂无回复内容~</div>
<div class="comments-loading" v-if="isShowGetCommentsLoading">
<i class="el-icon-loading"></i>
<span> 正在努力加载中~</span>
<span>正在努力加载中~</span>
</div>
<template v-else v-for="(item,index) in comments">
<div :key="index" class="item">
......@@ -98,7 +112,7 @@
<script>
import axios from "axios";
import { mapGetters } from "vuex";
import upload from '../../common/upload'
import upload from "../../common/upload";
export default {
name: "workorder-view",
data() {
......@@ -123,7 +137,7 @@ export default {
prop: Object
},
created() {
this.comments = []
this.comments = [];
},
computed: {
showData() {
......@@ -141,53 +155,109 @@ export default {
},
getWorkOrder() {
axios.get("/public/workorder/" + this.prop.id).then(response => {
if(response.data.data != null)this.workorder = response.data.data;
if (response.data.data != null) this.workorder = response.data.data;
setTimeout(() => this.$previewRefresh(), 500);
});
},
getComments() {
this.isShowGetCommentsLoading = true
axios.get("/public/workorder/comments/" + this.prop.id).then(response => {
if(response.data.data != null)this.comments = response.data.data;
this.isShowGetCommentsLoading = true;
axios
.get("/public/workorder/comments/" + this.prop.id)
.then(response => {
if (response.data.data != null) this.comments = response.data.data;
setTimeout(() => this.$previewRefresh(), 500);
this.isShowGetCommentsLoading = false
}).catch(error => {
this.isShowGetCommentsLoading = false;
})
.catch(error => {
console.log(error);
this.isShowGetCommentsLoading = false
this.$message.error('加载失败,请刷新尝试~');
this.isShowGetCommentsLoading = false;
this.$message.error("加载失败,请刷新尝试~");
});
},
closeWorkorder() {
this.$prompt("请输入关闭原因!", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
inputPattern: /\S/,
inputErrorMessage: "关闭工单原因不能为空~"
}).then(({ value }) => {
const wid = this.showData.id;
let remark = value
axios
.post("/workorder/close", { wid, remark })
.then(response => {
this.getWorkOrder()
this.$notify({
title: "温馨提示!",
message: "工单已关闭~",
showClose: false,
type: "success"
});
})
.catch(error => {
this.$message.error("工单关闭失败~");
});
});
},
delWorkorder() {
this.$confirm('您确定删除该工单吗?', '温馨提示!', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const wid = this.showData.id;
axios
.delete("/public/workorder/" +wid)
.then(response => {
this.$notify({
title: "温馨提示!",
message: "工单已删除~",
showClose: false,
type: "success"
});
this.close()
})
.catch(error => {
this.$message.error("工单删除失败~");
});
});
},
reply() {
const content = this.request.content + this.request.source;
if (content.trim() == "") {
this.$message.error('请输入内容~');
this.$message.error("请输入内容~");
return;
}
if (this.isSubmit) return;
this.isSubmit = true;
console.log(this.showData)
const wid = this.showData.id;
axios
.post("/public/workorder/reply", { wid, content })
.then(response => {
this.isSubmit = false
this.isSubmit = false;
console.log(response);
this.getComments();
this.request = {
source: "",
content: ""
};
this.$message.success('回复成功~');
setTimeout(()=>{
var sBoxHeight = document.querySelector(".content").clientHeight
var sHeight = document.querySelector(".scroll").clientHeight
document.querySelector(".content").scrollTop = sHeight - sBoxHeight + 20
}, 500)
this.$notify({
title: "温馨提示!",
message: "回复成功~",
showClose: false,
type: "success"
});
setTimeout(() => {
var sBoxHeight = document.querySelector(".content").clientHeight;
var sHeight = document.querySelector(".scroll").clientHeight;
document.querySelector(".content").scrollTop =
sHeight - sBoxHeight + 20;
}, 500);
})
.catch(error => {
this.isSubmit = false
this.isSubmit = false;
console.log(error);
this.$message.error('提交失败~');
this.$message.error("提交失败~");
});
},
inputBlur() {
......@@ -207,17 +277,29 @@ export default {
progress() {},
success(src) {
self.isShowUploadLoading = false;
var html
var html;
var fullPath = self.uploadToken.host + "/" + src;
var fileType = src.substr(src.lastIndexOf(".") + 1);
if ("jpg,jpeg,png,JPG,JPEG,PNG".indexOf(fileType) != -1) {
html = "<br><img style='max-width:45%' preview='1' src='" + fullPath + "' />"
}else{
html = "<br><img style='width:20px;height:20px;top:3px; right:3px;position: relative;' preview='1' src='http://qiniu.cmp520.com/fj.png' />"
html += "<a target='_blank' style='color: #2e9dfc;' href='"+fullPath+"'>下载附件</a>"
}
self.request.source = html
self.$message.success('上传成功~');
html =
"<br><img style='max-width:45%' preview='1' src='" +
fullPath +
"' />";
} else {
html =
"<br><img style='width:20px;height:20px;top:3px; right:3px;position: relative;' preview='1' src='http://qiniu.cmp520.com/fj.png' />";
html +=
"<a target='_blank' style='color: #2e9dfc;' href='" +
fullPath +
"'>下载附件</a>";
}
self.request.source = html;
self.$notify({
title: "温馨提示!",
message: "上传成功~",
showClose: false,
type: "success"
});
},
error(e) {
self.isShowUploadLoading = false;
......@@ -227,7 +309,7 @@ export default {
}
}
});
},
}
},
watch: {
prop() {
......@@ -261,7 +343,7 @@ export default {
font-size: 14px;
}
.workorder-close ,.comments-loading{
.workorder-close, .comments-loading {
text-align: center;
color: #666;
font-size: 14px;
......@@ -317,6 +399,7 @@ export default {
}
}
}
.content-box {
width: 600px;
height: 100%;
......@@ -329,19 +412,24 @@ export default {
overflow: hidden;
border-radius: 5px 5px 0 0;
padding-top: 40px;
padding-bottom 135px
padding-bottom: 135px;
box-sizing: border-box;
.content{
&.padding-bottom30{
padding-bottom: 30px;
}
.content {
box-sizing: border-box;
width 100%
width: 100%;
padding: 0 10px;
height: 100%;
overflow: hidden;
overflow-y: auto;
padding-top: 10px;
position relative
padding-bottom 20px
position: relative;
padding-bottom: 20px;
}
.file-view {
position: absolute;
bottom: 135px;
......@@ -351,6 +439,7 @@ export default {
margin: 0 auto;
font-size: 13px;
color: #8bc34a;
span {
display: flex;
align-content: center;
......@@ -367,6 +456,7 @@ export default {
}
}
}
.input-form {
position: absolute;
bottom: 35px;
......@@ -410,6 +500,7 @@ export default {
}
}
}
.title {
width: 100%;
height: 40px;
......@@ -422,6 +513,12 @@ export default {
box-sizing: border-box;
}
.buttons {
position: absolute;
top: 5px;
right: 50px;
}
.close {
position: absolute;
top: 5px;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment