Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/3033tags/v1.22.10.1^2
| @@ -707,6 +707,9 @@ var ( | |||
| NPU_MINDSPORE_IMAGE_ID int | |||
| NPU_TENSORFLOW_IMAGE_ID int | |||
| }{} | |||
| ModelApp = struct { | |||
| DesensitizationUrl string | |||
| }{} | |||
| ) | |||
| // DateLang transforms standard language locale name to corresponding value in datetime plugin. | |||
| @@ -1527,6 +1530,7 @@ func NewContext() { | |||
| getGrampusConfig() | |||
| getModelartsCDConfig() | |||
| getModelConvertConfig() | |||
| getModelAppConfig() | |||
| } | |||
| func getModelConvertConfig() { | |||
| @@ -1548,6 +1552,12 @@ func getModelConvertConfig() { | |||
| ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35) | |||
| } | |||
| func getModelAppConfig() { | |||
| sec := Cfg.Section("model_app") | |||
| ModelApp.DesensitizationUrl = sec.Key("desensitization_url").MustString("") | |||
| } | |||
| func getModelartsCDConfig() { | |||
| sec := Cfg.Section("modelarts-cd") | |||
| @@ -3261,3 +3261,8 @@ hours = Hours | |||
| expected_time = , expected to be available for | |||
| points_acquisition_instructions = Points Acquisition Instructions | |||
| insufficient_points_balance = Insufficient points balance | |||
| [model_app] | |||
| get_file_fail= Can not get the image content, please try again later. | |||
| content_type_unsupported=Allowed image type is jpg, jpeg or png. | |||
| process_image_fail=Fail to process image, please try again later. | |||
| @@ -3282,3 +3282,7 @@ points_acquisition_instructions = 积分获取说明 | |||
| insufficient_points_balance = 积分余额不足 | |||
| [model_app] | |||
| get_file_fail= 获取上传文件失败,请稍后再试。 | |||
| content_type_unsupported=请上传jpg、jpeg或png图片。 | |||
| process_image_fail=图片处理失败,请稍后再试。 | |||
| @@ -0,0 +1,78 @@ | |||
| package modelapp | |||
| import ( | |||
| "bytes" | |||
| "code.gitea.io/gitea/models" | |||
| "crypto/tls" | |||
| "image" | |||
| "image/png" | |||
| "net/http" | |||
| "strconv" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/modules/base" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "github.com/go-resty/resty/v2" | |||
| ) | |||
| var restyClient *resty.Client | |||
| var tplExploreUpload base.TplName = "model/tuomin/upload" | |||
| var uploadUrl = "/extension/tuomin/upload" | |||
| var allowedContentType = []string{"image/jpeg", "image/jpg", "image/png"} | |||
| func ProcessImageUI(ctx *context.Context) { | |||
| ctx.HTML(200, tplExploreUpload) | |||
| } | |||
| func ProcessImage(ctx *context.Context) { | |||
| file, header, err := ctx.GetFile("file") | |||
| if err != nil { | |||
| ctx.JSON(http.StatusBadRequest,models.BaseErrorMessage(ctx.Tr("model_app.get_file_fail"))) | |||
| return | |||
| } | |||
| defer file.Close() | |||
| contentType := header.Header.Get("Content-Type") | |||
| if !isInAllowedContentType(contentType) { | |||
| ctx.JSON(http.StatusBadRequest,models.BaseErrorMessage(ctx.Tr("model_app.content_type_unsupported"))) | |||
| return | |||
| } | |||
| client := getRestyClient() | |||
| res, err := client.R().SetMultipartField( | |||
| "file", header.Filename, contentType, file).Post(setting.ModelApp.DesensitizationUrl + "?mode=" + strconv.Itoa(ctx.QueryInt("mode"))) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusBadRequest,models.BaseErrorMessage(ctx.Tr("model_app.process_image_fail"))) | |||
| return | |||
| } | |||
| image, _, err := image.Decode(bytes.NewReader(res.Body())) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusBadRequest,models.BaseErrorMessage(ctx.Tr("model_app.process_image_fail"))) | |||
| return | |||
| } | |||
| png.Encode(ctx.Resp, image) | |||
| return | |||
| } | |||
| func isInAllowedContentType(contentType string) bool { | |||
| for _, allowType := range allowedContentType { | |||
| if allowType == contentType { | |||
| return true | |||
| } | |||
| } | |||
| return false | |||
| } | |||
| func getRestyClient() *resty.Client { | |||
| if restyClient == nil { | |||
| restyClient = resty.New() | |||
| restyClient.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) | |||
| } | |||
| return restyClient | |||
| } | |||
| @@ -6,15 +6,17 @@ package routes | |||
| import ( | |||
| "bytes" | |||
| "code.gitea.io/gitea/routers/reward/point" | |||
| "code.gitea.io/gitea/routers/task" | |||
| "code.gitea.io/gitea/services/reward" | |||
| "encoding/gob" | |||
| "net/http" | |||
| "path" | |||
| "text/template" | |||
| "time" | |||
| "code.gitea.io/gitea/routers/modelapp" | |||
| "code.gitea.io/gitea/routers/reward/point" | |||
| "code.gitea.io/gitea/routers/task" | |||
| "code.gitea.io/gitea/services/reward" | |||
| "code.gitea.io/gitea/modules/slideimage" | |||
| "code.gitea.io/gitea/routers/image" | |||
| @@ -346,6 +348,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Post("/user/login/kanban", user.SignInPostAPI) | |||
| m.Get("/home/term", routers.HomeTerm) | |||
| m.Get("/home/privacy", routers.HomePrivacy) | |||
| m.Get("/extension/tuomin/upload", modelapp.ProcessImageUI) | |||
| m.Post("/extension/tuomin/upload", reqSignIn, modelapp.ProcessImage) | |||
| m.Group("/explore", func() { | |||
| m.Get("", func(ctx *context.Context) { | |||
| ctx.Redirect(setting.AppSubURL + "/explore/repos") | |||
| @@ -32,9 +32,15 @@ | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui simple dropdown item" > | |||
| {{.i18n.Tr "repo.model_manager"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui simple dropdown item" id='dropdown_explore'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| @@ -68,6 +74,14 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui simple dropdown item" > | |||
| {{.i18n.Tr "repo.model_manager"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui simple dropdown item" id='dropdown_PageHome'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| @@ -34,6 +34,13 @@ | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui simple dropdown item" > | |||
| {{.i18n.Tr "repo.model_manager"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui dropdown item" id='dropdown_explore'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| @@ -66,6 +73,13 @@ | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui simple dropdown item" > | |||
| {{.i18n.Tr "repo.model_manager"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| @@ -26,6 +26,13 @@ | |||
| </div> | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui simple dropdown item" > | |||
| {{.i18n.Tr "repo.model_manager"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui dropdown item" id='dropdown_explore'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| @@ -59,6 +66,13 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui simple dropdown item" > | |||
| {{.i18n.Tr "repo.model_manager"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| @@ -36,6 +36,13 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui simple dropdown item" > | |||
| {{.i18n.Tr "repo.model_manager"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui dropdown item" id='dropdown_explore'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| @@ -69,6 +76,13 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
| <div class="ui simple dropdown item" > | |||
| {{.i18n.Tr "repo.model_manager"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/extension/tuomin/upload">模型体验</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| @@ -0,0 +1,12 @@ | |||
| {{template "base/head" .}} | |||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-model-tuomin.css?v={{MD5 AppVer}}" /> | |||
| <div> | |||
| {{if .Flash}} | |||
| <div class="sixteen wide column"> | |||
| {{template "base/alert" .}} | |||
| </div> | |||
| {{end}} | |||
| <div id="__vue-root"></div> | |||
| </div> | |||
| <script src="{{StaticUrlPrefix}}/js/vp-model-tuomin.js?v={{MD5 AppVer}}"></script> | |||
| {{template "base/footer" .}} | |||
| @@ -1,80 +0,0 @@ | |||
| {{template "base/head" .}} | |||
| <div class="organization members"> | |||
| {{template "org/header" .}} | |||
| <div class="ui container"> | |||
| {{template "base/alert" .}} | |||
| {{template "org/navber" .}} | |||
| <div class="ui stackable grid"> | |||
| <div class="ui sixteen wide computer column list"> | |||
| {{ range .Members}} | |||
| <div class="item ui grid"> | |||
| <div class="three wide mobile two wide tablet one wide computer column"> | |||
| <img class="ui avatar" src="{{.SizedRelAvatarLink 48}}"> | |||
| </div> | |||
| <div class="seven wide mobile three wide tablet three wide computer column"> | |||
| <div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div> | |||
| <div class="meta">{{.FullName}}</div> | |||
| </div> | |||
| <div class="ui three wide tablet four wide computer column center tablet only computer only"> | |||
| <div class="meta"> | |||
| {{$.i18n.Tr "org.members.membership_visibility"}} | |||
| </div> | |||
| <div class="meta"> | |||
| {{ $isPublic := index $.MembersIsPublicMember .ID}} | |||
| {{if $isPublic}} | |||
| <strong>{{$.i18n.Tr "org.members.public"}}</strong> | |||
| {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/private?uid={{.ID}}">{{$.i18n.Tr "org.members.public_helper"}}</a>){{end}} | |||
| {{else}} | |||
| <strong>{{$.i18n.Tr "org.members.private"}}</strong> | |||
| {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/public?uid={{.ID}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}} | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| <div class="five wide mobile three wide tablet three wide computer column"> | |||
| <div class="meta"> | |||
| {{$.i18n.Tr "org.members.member_role"}} | |||
| </div> | |||
| <div class="meta"> | |||
| <strong>{{if index $.MembersIsUserOrgOwner .ID}}{{svg "octicon-shield-lock" 16}} {{$.i18n.Tr "org.members.owner"}}{{else}}{{$.i18n.Tr "org.members.member"}}{{end}}</strong> | |||
| </div> | |||
| </div> | |||
| <div class="ui one wide column center tablet only computer only"> | |||
| <div class="meta"> | |||
| 2FA | |||
| </div> | |||
| <div class="meta"> | |||
| <strong> | |||
| {{if index $.MembersTwoFaStatus .ID}} | |||
| <span class="text green">{{svg "octicon-check" 16}}</span> | |||
| {{else}} | |||
| {{svg "octicon-x" 16}} | |||
| {{end}} | |||
| </strong> | |||
| </div> | |||
| </div> | |||
| <div class="ui three wide column tablet only computer only"> | |||
| <div class="text right"> | |||
| {{if eq $.SignedUser.ID .ID}} | |||
| <form method="post" action="{{$.OrgLink}}/members/action/leave"> | |||
| {{$.CsrfTokenHtml}} | |||
| <button type="submit" class="ui red small button" name="uid" value="{{.ID}}">{{$.i18n.Tr "org.members.leave"}}</button> | |||
| </form> | |||
| {{else if $.IsOrganizationOwner}} | |||
| <form method="post" action="{{$.OrgLink}}/members/action/remove"> | |||
| {{$.CsrfTokenHtml}} | |||
| <button type="submit" class="ui red small button" name="uid" value="{{.ID}}">{{$.i18n.Tr "org.members.remove"}}</button> | |||
| </form> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{end}} | |||
| </div> | |||
| {{template "base/paginate" .}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -176,6 +176,22 @@ const en = { | |||
| Activated: 'Activated', | |||
| notActive: 'Not active', | |||
| }, | |||
| tranformImageFailed:'Picture desensitization failed', | |||
| originPicture:'Origin picture', | |||
| desensitizationPicture:'Desensitization picture', | |||
| desensitizationObject:'Desensitization object', | |||
| example:'Example', | |||
| startDesensitization:'Start desensitization', | |||
| all:'All', | |||
| onlyFace:'Only face', | |||
| onlyLicensePlate:'Only license plate', | |||
| dragThePictureHere:'Drag the picture here', | |||
| or:'or', | |||
| clickUpload:'Click upload', | |||
| dataDesensitizationModelExperience:'Data desensitization model experience', | |||
| dataDesensitizationModelDesc:'Use AI technology to desensitize the face and license plate number in the picture. For more information about this model, please visit the project', | |||
| limitFilesUpload:'Only jpg/jpeg/png files can be uploaded', | |||
| limitSizeUpload:'The size of the uploaded file cannot exceed 20M!', | |||
| } | |||
| export default en; | |||
| @@ -176,6 +176,22 @@ const zh = { | |||
| Activated: '已激活', | |||
| notActive: '未激活', | |||
| }, | |||
| tranformImageFailed:'图片脱敏失败', | |||
| originPicture:'原始图片', | |||
| desensitizationPicture:'脱敏图片', | |||
| desensitizationObject:'脱敏对象', | |||
| example:'示例', | |||
| startDesensitization:'开始处理', | |||
| all:'全部', | |||
| onlyFace:'仅人脸', | |||
| onlyLicensePlate:'仅车牌', | |||
| dragThePictureHere:'拖动图片到这里', | |||
| or:'或', | |||
| clickUpload:'点击上传', | |||
| dataDesensitizationModelExperience:'数据脱敏模型体验', | |||
| dataDesensitizationModelDesc:'利用人工智能AI技术,把图片中的人脸、车牌号码进行脱敏处理。该模型更多信息请访问项目', | |||
| limitFilesUpload:'只能上传 jpg/jpeg/png 格式的文件', | |||
| limitSizeUpload:'上传文件大小不能超过 20M !', | |||
| } | |||
| export default zh; | |||
| @@ -0,0 +1,380 @@ | |||
| <template> | |||
| <div class="ui container"> | |||
| <div class="tuomin-title"> | |||
| <h2>{{ $t("dataDesensitizationModelExperience") }}</h2> | |||
| <p> | |||
| {{ $t("dataDesensitizationModelDesc") }} <a | |||
| href="https://git.openi.org.cn/tengxiao/tuomin" | |||
| target="_blank" | |||
| >tengxiao / tuomin</a | |||
| > | |||
| </p> | |||
| </div> | |||
| <el-row :gutter="12" style="margin-top: 33px"> | |||
| <el-col :xs="24" :span="12"> | |||
| <div class="tuomin-content-image"> | |||
| <div class="tuomin-icon"> | |||
| <i | |||
| class="ri-image-line" | |||
| style="font-size: 16px; margin-right: 2px" | |||
| ></i> | |||
| <span style="font-size: 12px">img</span> | |||
| </div> | |||
| <div style="height: 230px; width: 96%; margin: 0 auto"> | |||
| <el-upload | |||
| action="#" | |||
| accept=".jpg,.jpeg,.png,.JPG,.JPEG,.PNG" | |||
| :show-file-list="false" | |||
| :on-change="handleChangePicture" | |||
| list-type="picture-card" | |||
| :file-list="fileList" | |||
| :style="{ display: ImageUrl ? 'none' : 'block' }" | |||
| :auto-upload="false" | |||
| drag | |||
| > | |||
| <div class="el-upload__text"> | |||
| {{ $t("dragThePictureHere") | |||
| }}<span style="color: rgba(136, 136, 136, 0.87)">{{ | |||
| $t("or") | |||
| }}</span | |||
| >{{ $t("clickUpload") }} | |||
| </div> | |||
| </el-upload> | |||
| <img class="preview-image" v-if="ImageUrl" :src="ImageUrl" alt="" /> | |||
| </div> | |||
| <div> | |||
| <div class="tuomin-radio-model"> | |||
| <label class="radio-label" | |||
| >{{ $t("desensitizationObject") }}:</label | |||
| > | |||
| <div> | |||
| <el-radio-group v-model="radio"> | |||
| <el-radio :label="2">{{ $t("all") }}</el-radio> | |||
| <el-radio :label="1">{{ $t("onlyFace") }}</el-radio> | |||
| <el-radio :label="0">{{ $t("onlyLicensePlate") }}</el-radio> | |||
| </el-radio-group> | |||
| </div> | |||
| </div> | |||
| <div class="tuomin-button-model"> | |||
| <el-button @click="cancelUpload">{{ $t("cancel") }}</el-button> | |||
| <el-button | |||
| :disabled="fileList.length < 1" | |||
| @click="startTranform" | |||
| type="primary" | |||
| >{{ $t("startDesensitization") }}</el-button | |||
| > | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </el-col> | |||
| <el-col :xs="24" :span="12"> | |||
| <div class="tuomin-content-image" v-loading="tranformImageLoading"> | |||
| <div class="tuomin-icon"> | |||
| <i | |||
| class="ri-image-line" | |||
| style="font-size: 16px; margin-right: 2px" | |||
| ></i> | |||
| <span style="font-size: 12px">output</span> | |||
| </div> | |||
| <div | |||
| v-if="resultImgSrc" | |||
| class="tuomin-icon-download" | |||
| @click="downImg" | |||
| > | |||
| <i | |||
| class="ri-download-2-line" | |||
| style="font-size: 16px; margin-right: 2px" | |||
| ></i> | |||
| <span style="font-size: 14px">下载</span> | |||
| </div> | |||
| <div style="height: 358px"> | |||
| <el-image | |||
| style="height: 100%; width: 100%" | |||
| :src="resultImgSrc" | |||
| :preview-src-list="[resultImgSrc]" | |||
| > | |||
| <div slot="error" class="image-slot"> | |||
| <i style="font-size: 0" class="el-icon-picture-outline"></i> | |||
| </div> | |||
| </el-image> | |||
| </div> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <div style="margin: 39px 0 21px 0"> | |||
| <span>{{ $t("example") }}:</span> | |||
| </div> | |||
| <div class="table-container"> | |||
| <div> | |||
| <el-table border :data="tableData1" style="width: 100%"> | |||
| <el-table-column :label="$t('originPicture')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <div style="width: 100%; height: 200px"> | |||
| <el-image | |||
| style="height: 100%; width: 100%" | |||
| :src="scope.row.imgSrc1" | |||
| :preview-src-list="[scope.row.imgSrc1]" | |||
| > | |||
| <div slot="error" class="image-slot"> | |||
| <i style="font-size: 0" class="el-icon-picture-outline"></i> | |||
| </div> | |||
| </el-image> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column :label="$t('desensitizationPicture')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <div style="width: 100%; height: 200px"> | |||
| <el-image | |||
| style="height: 100%; width: 100%" | |||
| :src="scope.row.imgSrc2" | |||
| :preview-src-list="[scope.row.imgSrc2]" | |||
| > | |||
| <div slot="error" class="image-slot"> | |||
| <i style="font-size: 0" class="el-icon-picture-outline"></i> | |||
| </div> | |||
| </el-image> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="mode" | |||
| :label="$t('desensitizationObject')" | |||
| align="center" | |||
| header-align="center" | |||
| > | |||
| </el-table-column> | |||
| </el-table> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| import axios from "axios"; | |||
| export default { | |||
| data() { | |||
| return { | |||
| ImageUrl: "", | |||
| radio: 2, | |||
| file: "", | |||
| fileList: [], | |||
| resultImgSrc: "", | |||
| tranformImageLoading: false, | |||
| tableData1: [ | |||
| { | |||
| imgSrc1: "/img/origin.png", | |||
| imgSrc2: "/img/tuomin.png", | |||
| mode: this.$t("all"), | |||
| }, | |||
| ], | |||
| }; | |||
| }, | |||
| components: {}, | |||
| methods: { | |||
| // 选择文件、移除文件、上传文件成功/失败后,都会触发 | |||
| handleChangePicture(file, fileList) { | |||
| let acceptList = ["jpg", "jpeg", "png"]; | |||
| // 根据文件名获取文件的后缀名 | |||
| let fileType = file.name.split(".").pop().toLowerCase(); | |||
| // 判断文件格式是否符合要求 | |||
| if (acceptList.indexOf(fileType) === -1) { | |||
| this.$message.error(this.$t("limitFilesUpload")); | |||
| return false; | |||
| } | |||
| // 判断文件大小是否符合要求 | |||
| if (file.size / 1024 / 1024 > 20) { | |||
| this.$message.error(this.$t("limitSizeUpload")); | |||
| return false; | |||
| } | |||
| this.ImageUrl = URL.createObjectURL(file.raw); | |||
| this.file = file; | |||
| this.fileList = fileList; | |||
| }, | |||
| cancelUpload() { | |||
| this.ImageUrl = ""; | |||
| this.file = ""; | |||
| this.fileList = []; | |||
| }, | |||
| downImg() { | |||
| const a = document.createElement("a"); | |||
| a.download = "result.png"; | |||
| a.style.display = "none"; | |||
| a.href = this.resultImgSrc; | |||
| document.body.appendChild(a); | |||
| a.click(); | |||
| document.body.removeChild(a); | |||
| }, | |||
| startTranform() { | |||
| if (!this.file) return; | |||
| let fd = new FormData(); | |||
| fd.append("file", this.file.raw); | |||
| this.tranformImageLoading = true; | |||
| axios({ | |||
| method: "POST", | |||
| url: "/extension/tuomin/upload", | |||
| headers: { Accept: "image/png" }, | |||
| responseType: "blob", | |||
| params: { mode: this.radio }, | |||
| data: fd, | |||
| }) | |||
| .then((res) => { | |||
| const objectURL = URL.createObjectURL(res.data); | |||
| this.resultImgSrc = objectURL; | |||
| this.tranformImageLoading = false; | |||
| }) | |||
| .catch((err) => { | |||
| this.tranformImageLoading = false; | |||
| if (err.response.status === 400) { | |||
| const fr = new FileReader(); | |||
| fr.onload = (e) => { | |||
| try { | |||
| const jsonResult = JSON.parse(e.target.result); | |||
| this.$message({ | |||
| type: "error", | |||
| message: jsonResult.Message, | |||
| }); | |||
| } catch (e) { | |||
| this.$message({ | |||
| type: "error", | |||
| message: this.$t("tranformImageFailed"), | |||
| }); | |||
| } | |||
| }; | |||
| fr.readAsText(err.response.data); | |||
| } else { | |||
| this.$message({ | |||
| type: "error", | |||
| message: this.$t("tranformImageFailed"), | |||
| }); | |||
| } | |||
| }); | |||
| }, | |||
| }, | |||
| mounted() {}, | |||
| beforeDestroy() {}, | |||
| }; | |||
| </script> | |||
| <style scoped lang="less"> | |||
| .tuomin-title { | |||
| margin-top: 34px; | |||
| h2 { | |||
| display: flex; | |||
| justify-content: center; | |||
| } | |||
| p { | |||
| display: flex; | |||
| justify-content: center; | |||
| color: rgba(136, 136, 136, 0.87); | |||
| } | |||
| } | |||
| .tuomin-content-image { | |||
| border: 1px solid rgba(0, 0, 0, 0.1); | |||
| border-radius: 5px; | |||
| min-height: 358px; | |||
| position: relative; | |||
| .tuomin-icon { | |||
| z-index: 99; | |||
| display: flex; | |||
| align-items: center; | |||
| position: absolute; | |||
| left: 0; | |||
| top: 0; | |||
| width: 66px; | |||
| height: 22px; | |||
| justify-content: center; | |||
| color: rgba(136, 136, 136, 0.87); | |||
| border-radius: 5px 0px 10px 0px; | |||
| border: 1px solid rgba(0, 0, 0, 0.1); | |||
| } | |||
| .tuomin-icon-download { | |||
| z-index: 99; | |||
| display: flex; | |||
| align-items: center; | |||
| position: absolute; | |||
| right: 10px; | |||
| bottom: 10px; | |||
| width: 66px; | |||
| height: 30px; | |||
| justify-content: center; | |||
| color: rgba(255, 255, 255, 1); | |||
| background-color: rgba(0, 0, 0, 0); | |||
| background: transparent; | |||
| border: 1px solid rgba(136, 136, 136, 0.5); | |||
| border-radius: 4px; | |||
| cursor: pointer; | |||
| } | |||
| .el-upload__text { | |||
| height: 100%; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| } | |||
| .preview-image { | |||
| height: 100%; | |||
| width: 100%; | |||
| } | |||
| .tuomin-radio-model { | |||
| display: flex; | |||
| margin: 25px 12px 0 12px; | |||
| .radio-label { | |||
| font-weight: 600; | |||
| margin-right: 4px; | |||
| color: rgba(16, 16, 16, 1); | |||
| } | |||
| } | |||
| .tuomin-button-model { | |||
| text-align: right; | |||
| margin: 22px 12px 0 12px; | |||
| } | |||
| } | |||
| /deep/ .el-upload--picture-card { | |||
| width: 100%; | |||
| background: #ffff; | |||
| border: none; | |||
| border-bottom: 1px dashed #888; | |||
| border-radius: 0; | |||
| min-height: 230px; | |||
| } | |||
| /deep/ .el-upload-dragger { | |||
| width: 100%; | |||
| background: #ffff; | |||
| border: none; | |||
| border-radius: 0; | |||
| height: 100%; | |||
| } | |||
| .table-container { | |||
| margin-bottom: 16px; | |||
| /deep/ .el-table__header { | |||
| th { | |||
| background: rgb(245, 245, 246); | |||
| font-size: 14px; | |||
| color: rgb(36, 36, 36); | |||
| font-weight: 400; | |||
| } | |||
| } | |||
| /deep/ .el-table__body { | |||
| td { | |||
| font-size: 14px; | |||
| } | |||
| } | |||
| } | |||
| .center { | |||
| display: flex; | |||
| justify-content: center; | |||
| } | |||
| @media screen and (max-width: 768px) { | |||
| body { | |||
| background-color: black; | |||
| } | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,17 @@ | |||
| import Vue from 'vue'; | |||
| import ElementUI from 'element-ui'; | |||
| import 'element-ui/lib/theme-chalk/index.css'; | |||
| import localeEn from 'element-ui/lib/locale/lang/en'; | |||
| import localeZh from 'element-ui/lib/locale/lang/zh-CN'; | |||
| import { i18n, lang } from '~/langs'; | |||
| import App from './index.vue'; | |||
| Vue.use(ElementUI, { | |||
| locale: lang === 'zh-CN' ? localeZh : localeEn, | |||
| size: 'small', | |||
| }); | |||
| new Vue({ | |||
| i18n, | |||
| render: (h) => h(App), | |||
| }).$mount('#__vue-root'); | |||