Greasy Fork

Greasy Fork is available in English.

SZU mailbox

try to take over the world!

当前为 2021-02-08 提交的版本,查看 最新版本

// ==UserScript==
// @name         SZU mailbox
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       nut
// @match        https://www1.szu.edu.cn/mailbox/*
// @grant        unsafeWindow
// @require      https://cdn.bootcss.com/vue/2.6.11/vue.min.js
// @require      https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.0/index.min.js
// @run-at       document-start

// ==/UserScript==
unsafeWindow.onload = function () {
  function getQueryVariable(variable) {
    const query = window.location.search.substring(1);
    const vars = query.split("&");
    for (let i = 0; i < vars.length; i++) {
      const pair = vars[i].split("=");
      if (pair[0] == variable) {
        return pair[1];
      }
    }
    return (false);
  }
  if (!getQueryVariable("id")) return
  let scriptCss = document.createElement('link');
  scriptCss.setAttribute('rel', 'stylesheet');
  scriptCss.setAttribute('type', 'text/css');
  scriptCss.href = "https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.0/theme-chalk/index.min.css";
  document.documentElement.appendChild(scriptCss);

  let classCss = document.createElement('Style');
  classCss.innerHTML =
    `
    .cell {
      font-size: 14px;
    }

    .el-message-box__btns span {
      color: #000000;
      font-size: 12px;
      line-height: 100%;
    }

    .text-buttonSelect span {
      color: #409eff;
      font-family: 微软雅黑;
      font-size: 14px;
      line-height: 100%;
    }

    .text-dangerous-buttonSelect span {
      color: #F56C6C;
      font-family: 微软雅黑;
      font-size: 14px;
      line-height: 100%;
    }

    .text-buttonSelect:active span {
      color: #006dda;
    }

    .text-dangerous-buttonSelect:active span {
      color: #d33d3d;
    }

    .buttonSelect span {
      color: #fff;
      font-family: 微软雅黑;
      font-size: 14px;
      line-height: 100%;
    }

    .userName {
      margin: 7px 0 9px 0;
    }

    .avatar {
      margin-top: 12px;
      width: 80px;
      height: 80px;
    }

    .avatar2 {
      margin-top: 5px;
      width: 32px;
      height: 32px;
    }

    .commentContent {
      min-height: 97px;
    }
`
  document.documentElement.appendChild(classCss);

  let father = document.querySelector("body > table > tbody > tr:nth-child(2) > td > table > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(2) > td")

  let divApp = document.createElement('div')
  divApp.id = 'app'
  divApp.style = "width:980px;"

  divApp.innerHTML =
    `
    <el-main v-if="postId!=0" class="my_table" style="width:90%;padding:0;">
      <el-table :header-cell-style="headerStyle" :stripe="false" :data="comment" v-loading="loading"
        :cell-style="columnStyle">
        <el-table-column align="center" :label="'评论:' + total" width="98">
          <template slot-scope="scope">
            <el-col>
              <el-image class="avatar" src="https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png"
                fit="cover" lazy>
              </el-image>
            </el-col>
            <el-col class="userName">{{ scope.row.user }}</el-col>
          </template>
        </el-table-column>
        <el-table-column className="cols" label="content">
          <template slot="header" slot-scope="scope">
            <el-row type="flex" align="middle">
              <el-col :span="18"></el-col>
              <el-col :span="3">
                <el-button class="buttonSelect" size="small" type="primary" @click="postComment()">评论</el-button>
              </el-col>
              <el-col :span="3">
                <el-button class="buttonSelect" size="small" type="primary" @click="getComment()">刷新</el-button>
              </el-col>
              <el-col :span="3">
                <el-button class="buttonSelect" size="small" :disabled="true" type="primary"
                  @click="sortComment(scope.$index, scope.row)">
                  按时间:
                  {{ sort == "id" ? "旧" : "新" }}</el-button>
              </el-col>
            </el-row>
          </template>
          <template slot-scope="scope">
            <div class="commentContent">{{scope.row.content}}</div>
            <el-row type="flex" align="middle">
              <el-col :span="2">
                <div style="min-width: 27px">
                  {{ scope.row.level + "楼" }}
                </div>
              </el-col>
              <el-col :span="18">
                {{ scope.row.time.substring(0, 10) }}
                {{ scope.row.time.substring(11, 16) }}
              </el-col>
              <el-col :span="3">
                <el-button class="buttonSelect" v-if="uuid==scope.row.uuid" size="mini"
                  @click="deleteComment(scope.row.id, scope.$index)" type="danger">
                  删除
                </el-button>
              </el-col>
              <el-col :span="3">
                <el-badge :value="scope.row.replies.total" type="primary">
                  <el-button class="buttonSelect" size="mini" type="primary" @click="popReply(scope.$index)">回复
                  </el-button>
                </el-badge>
              </el-col>
            </el-row>
            <el-row>
              <el-collapse-transition>
                <div v-show="comment[scope.$index].reply.showReply" style="margin-top:10px;">
                  <el-table :data="scope.row.replies.replies" :show-header="false" :cell-style="replycolumnStyle"
                    v-loading="comment[scope.$index].reply.loading">
                    <el-table-column align="center" width="52" label="head">
                      <template>
                        <el-image class="avatar2"
                          src="https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png" fit="cover" lazy>
                        </el-image>
                      </template>
                    </el-table-column>
                    <el-table-column className="cols" label="content">
                      <template slot-scope="item">
                        <el-row :style="'height:'+ item.row.height +'px'">
                          {{ item.row.user + " :  "+ (item.row.number?('@' + item.row.repliedUser+' : '):"") + item.row.content}}
                        </el-row>
                        <el-row style="height:23px" type="flex" align="middle" justify="end">
                          <el-col :span="16">
                            <div style="min-width: 27px">
                              {{ item.row.level + "层" }}
                            </div>
                          </el-col>
                          <el-col :span="2">
                            <el-button v-if="uuid==scope.row.uuid" style="padding: 0;" type="text"
                              class="text-dangerous-buttonSelect"
                              @click="deleteReply(item.row.id, item.$index,scope.$index)"> 删除
                            </el-button>
                          </el-col>
                          <el-col :span="4" style="font-family: Avenir, Helvetica, Arial, sans-serif;">
                            {{ item.row.time.substring(0, 10) }}
                            {{ item.row.time.substring(11, 16) }}
                          </el-col>
                          <el-col :span="2">
                            <el-button style="padding: 0;" type="text" class="text-buttonSelect"
                              @click="postReply(scope.$index,item.row.level,item.row.user,item.row.id)">回复
                            </el-button>
                          </el-col>
                        </el-row>
                      </template>
                    </el-table-column>
                  </el-table>
                  <el-row type="flex" align="middle" justify="end">
                    <el-col>
                      <el-pagination v-if="comment[scope.$index].replies.total != 0" small layout="prev, pager, next"
                        :total="comment[scope.$index].replies.total"
                        :current-page.sync="comment[scope.$index].reply.currentPage" :page-size="limit"
                        @current-change="getReply(scope.$index)">
                      </el-pagination>
                    </el-col>
                    <el-col :span="3">
                      <el-button style="padding: 0;" type="text" class="text-buttonSelect"
                        @click="postReply(scope.$index,0,scope.row.user,scope.row.id)">
                        回复一下
                      </el-button>
                    </el-col>
                  </el-row>
                  <el-collapse-transition>
                    <el-card v-show="comment[scope.$index].reply.showInput">
                      <el-row style="margin-bottom:10px">
                        <el-input v-model="scope.row.reply.content" placeholder="请写下你的回复">
                          <template v-if="scope.row.reply.number"
                            slot="prepend">{{'@'+scope.row.reply.repliedUser}}</template>
                        </el-input>
                      </el-row>
                      <el-row type="flex" align="middle">
                        <el-col :span="2" :offset="19">
                          <el-checkbox v-model="scope.row.reply.isAnonymous">匿名</el-checkbox>
                        </el-col>
                        <el-col :span="2">
                          <el-button class="buttonSelect" size="mini" type="primary" @click="replySubmit(scope.$index)">
                            发送
                          </el-button>
                        </el-col>
                      </el-row>
                    </el-card>
                  </el-collapse-transition>
                </div>
              </el-collapse-transition>
            </el-row>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination style="text-align: center; margin: 10px 0 10px 0" background layout="prev, pager, next"
        :total="total" :current-page.sync="currentPage" :page-size="limit" @current-change="getComment()">
      </el-pagination>
      <el-card>
        <el-row style="margin-bottom:10px">
          <el-input type="textarea" :autosize="{ minRows: 3}" v-model="content" placeholder="请写下你的评论">
          </el-input>
        </el-row>
        <el-row type="flex" align="middle">
          <el-col :span="2" :offset="20">
            <el-checkbox v-model="isAnonymous">匿名</el-checkbox>
          </el-col>
          <el-col :span="2">
            <el-button class="buttonSelect" size="mini" type="primary" @click="commentSubmit()">发送</el-button>
          </el-col>
        </el-row>
        <div id="commentEdit" style="position:relative;top:80px"></div>
        <div id='textLength' style='font-family: Avenir, Helvetica, Arial, sans-serif; white-space: nowrap;
         position:fixed;z-index:-1;bottom:0;opacity:0;height:0;font-size:14px'></div>
      </el-card>
    </el-main>
  `

  father.append(divApp)

  new Vue({
    el: '#app',
    data() {
      return {
        loading: true,
        currentPage: 1,
        total: 0,
        limit: 10,
        postId: 0,

        comment: [],
        sort: "id",
        uuid: '1',
        input: '',
        content: '',
        isAnonymous: 0,

      }
    },
    mounted() {
      this.init().then(res => {
        sessionStorage.setItem('uuid', JSON.parse(res).uuid)
        this.uuid = sessionStorage.getItem('uuid')
      })
      if (!this.getQueryVariable("id")) return
      else this.postId = this.getQueryVariable("id")
      this.getComment()
    },
    methods: {
      async init() {
        const xml = new XMLHttpRequest();
        xml.open('GET', "https://mailbox.nutvii.top/login/");
        xml.withCredentials = true
        xml.setRequestHeader('Authorization', this.getASPSESSION());
        xml.send();
        return new Promise((resolve) => {
          xml.onload = () => {
            resolve(xml.responseText)
          }
        })
      },
      getASPSESSION() {
        let cookieStr = document.cookie.split('; ');
        let cookies = "null";
        let isFirst = true;
        for (const i in cookieStr) {
          if (cookieStr[i].indexOf("ASPSESSION") !== -1) {
            if (isFirst) {
              cookies = cookieStr[i];
              isFirst = false;
            } else {
              cookies += '; ' + cookieStr[i];
            }
          }
        }
        return cookies
      },
      async httpMethod(method, url, data) {
        url = 'https://mailbox.nutvii.top/' + url
        const xml = new XMLHttpRequest();
        xml.withCredentials = true
        let str = '';
        let isFirst = true;
        for (const i in data) {
          if (isFirst) {
            isFirst = false;
            str += i + '=' + data[i]
          } else str += '&' + i + '=' + data[i]
        }

        if (method == 'GET' || method == 'DELETE') {
          xml.open(method, url + '?' + str);
          xml.send(null);
        } else if (method == 'POST') {
          xml.open(method, url);
          xml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
          xml.send(str);
        }
        return new Promise((resolve, reject) => {
          xml.onload = () => {
            if (xml.status == 200) resolve(JSON.parse(xml.responseText))
            else reject(xml.responseText);
          }
        })
      },
      getComment() {
        this.loading = true;
        this.httpMethod('GET', 'comment/', {
          'postId': this.postId,
          'limit': this.limit,
          'offset': this.currentPage,
        }).then((data) => {
          this.comment = data.comments
          for (const i in this.comment) {
            this.$set(this.comment[i], 'reply', {
              'commentId': this.comment[i].id,
              'content': '',
              'number': 0,
              'repliedId': this.comment[i].id,
              'isAnonymous': 0,
              'repliedUser': '',
              'showReply': false,
              'showInput': false,
              'loading': false,
              'currentPage': 1
            })
            const rArr = this.comment[i].replies.replies
            for (const j in rArr) {
              let str = rArr[j].user + " :  "
              str += (rArr[j].number ? ('@' + rArr[j].repliedUser + ' : ') : "") + rArr[j].content
              this.$set(rArr[j], 'height', this.getLength(str))
            }
            this.comment[i].reply.showReply = this.comment[i].replies.total != 0
          }
          this.total = data.total
          this.loading = false
        }).catch((e) => {
          this.$message.error(e)
        })
      },
      postComment() {
        document.getElementById("commentEdit").scrollIntoView({
          block: 'end',
          behavior: 'smooth'
        })
      },
      commentSubmit() {
        if (this.content.length >= 3) {
          this.httpMethod('POST', 'comment/', {
            'postId': this.postId,
            'content': this.content,
            'isAnonymous': this.isAnonymous ? 1 : 0,
          }).then((data) => {
            this.$message.success('评论成功')
            this.total++;
            if (Math.ceil((this.total) / 10) > this.currentPage) {
              this.currentPage = Math.ceil(this.total / 10)
              this.getComment()
            } else {
              data['replies'] = {}
              this.$set(data, 'reply', {
                'commentId': data.id,
                'content': '',
                'number': 0,
                'repliedId': data.id,
                'isAnonymous': 0,
                'repliedUser': '',
                'showReply': false,
                'showInput': false,
                'loading': false,
                'currentPage': 1
              })
              this.comment.push(data)
            }
            this.content = ''
          }).catch((e) => {
            this.$message.error(e)
          })
        } else {
          this.$message.error("字数少于3")
        }
      },
      deleteComment(id, index) {
        this.$confirm('确认删除?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.httpMethod('DELETE', 'comment/', {
            'id': id
          }).then((data) => {
            this.$message.success('删除成功')
            this.comment.splice(index, 1)
            this.total--;
          }).catch((e) => {
            this.$message.error(e)
          })
        })
      },
      getReply(index) {
        this.comment[index].reply.loading = true
        this.httpMethod('GET', 'reply/', {
          'commentId': this.comment[index].id,
          'limit': this.limit,
          'offset': this.comment[index].reply.currentPage,
        }).then((data) => {
          for (const i in data) {
            if (i == 'replies') {
              for (const j in data[i]) {
                let str = data[i][j].user + " :  "
                str += (data[i][j].number ? ('@' + data[i][j].repliedUser + ' : ') : "") + data[i][j].content
                this.$set(data[i][j], 'height', this.getLength(str))
              }
            }
            this.comment[index].replies[i] = data[i]
          }
          this.comment[index].reply.loading = false
        }).catch((e) => {
          this.$message.error(e)
        })
      },
      popReply(index) {
        this.comment[index].reply.showReply = !this.comment[index].reply.showReply
      },
      postReply(index, level, repliedUser, repliedId) {
        if (this.comment[index].reply.showInput && level == this.comment[index].reply.number)
          this.comment[index].reply.showInput = false
        else this.comment[index].reply.showInput = true
        this.comment[index].reply.number = level
        this.comment[index].reply.repliedUser = repliedUser
        this.comment[index].reply.repliedId = repliedId
      },
      replySubmit(index) {
        if (this.comment[index].reply.content.length >= 3) {
          this.httpMethod('POST', 'reply/', {
            'commentId': this.comment[index].reply.commentId,
            'content': this.comment[index].reply.content,
            'number': this.comment[index].reply.number,
            'repliedId': this.comment[index].reply.repliedId,
            'isAnonymous': this.comment[index].reply.isAnonymous ? 1 : 0,
          }).then((data) => {
            this.$message.success('回复成功')
            this.comment[index].replies.total++;
            if (Math.ceil((this.comment[index].replies.total) / 10) > this.comment[index].reply.currentPage) {
              this.comment[index].reply.currentPage = Math.ceil(this.comment[index].replies.total / 10)
              this.getReply(index)
            } else {
              let str = data.user + " :  "
              str += (data.number ? ('@' + data.repliedUser + ' : ') : "") + data.content
              this.$set(data, 'height', this.getLength(str))
              this.comment[index].replies.replies.push(data)
            }
            this.comment[index].reply.content = ''
            this.content = ''
          }).catch((e) => {
            this.$message.error(e)
          })
        } else {
          this.$message.error("字数少于3")
        }
      },
      deleteReply(id, index, commentIndex) {
        this.$confirm('确认删除?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.httpMethod('DELETE', 'reply/', {
            'id': id
          }).then((data) => {
            this.$message.success('删除成功')
            this.comment[commentIndex].replies.replies.splice(index, 1)
            this.comment[commentIndex].replies.total--;
          }).catch((e) => {
            this.$message.error(e)
          })
        })
      },
      sortComment(index, row) {
        this.sort = this.sort == 'id' ? '-id' : 'id';
        this.$set(this.comment, index, row)
        this.getComment()
      },
      columnStyle({
        row,
        column,
        rowIndex,
        columnIndex
      }) {
        if (columnIndex == 0) return 'background:#cddade;vertical-align:top;'
        else return 'background:#fff;vertical-align:top;'
      },
      replycolumnStyle({
        row,
        column,
        rowIndex,
        columnIndex
      }) {
        return 'background:#f5f6f7;vertical-align:top;padding:5px;'
      },
      headerStyle({
        row,
        column,
        rowIndex,
        columnIndex
      }) {
        if (columnIndex == 0) return 'background:#ebeef5;'
      },
      getQueryVariable(variable) {
        const query = window.location.search.substring(1);
        const vars = query.split("&");
        for (let i = 0; i < vars.length; i++) {
          const pair = vars[i].split("=");
          if (pair[0] == variable) {
            return pair[1];
          }
        }
        return (false);
      },
      getLength(str) {
        const ele = document.getElementById('textLength')
        ele.textContent = str
        const length = ele.clientWidth
        ele.textContent = ''
        return Math.ceil(length / 682) * 23
      }
    }
  })
}