Junjie
2026-04-07 cd448f774cfd4837a969d01ebea03530608c6839
src/main/webapp/views/apkBuild/apkBuild.html
@@ -224,7 +224,7 @@
                    <el-table-column label="操作" width="180" align="center" fixed="right">
                        <template slot-scope="scope">
                            <el-button type="text" size="small" @click="showDetail(scope.row)">详情</el-button>
                            <el-button type="text" size="small" v-if="scope.row.status === 2 && !scope.row.apkPath"
                            <el-button type="text" size="small" v-if="scope.row.status === 2 && scope.row.apkPath"
                                @click="downloadApk(scope.row)" :loading="scope.row.downloading">下载</el-button>
                            <el-button type="text" size="small" style="color: #67c23a;"
                                v-if="scope.row.status === 2 && scope.row.apkPath"
@@ -252,12 +252,22 @@
                        <el-radio label="debug">Debug</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="目标类型" prop="android_target">
                    <el-select v-model="buildForm.android_target" placeholder="请选择目标类型" style="width: 100%;">
                        <el-option label="TV" value="tv"></el-option>
                        <el-option label="PDA" value="pda"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="仓库别名" prop="repoAlias">
                    <el-input v-model="buildForm.repoAlias" placeholder="请输入仓库别名"></el-input>
                </el-form-item>
                <el-form-item label="分支名称" prop="branch">
                    <el-input v-model="buildForm.branch" placeholder="请输入分支名称"></el-input>
                    <div class="form-tip">默认为 master 分支</div>
                </el-form-item>
                <el-form-item label="服务器地址" prop="server_url">
                    <el-input v-model="buildForm.server_url" placeholder="请输入 server_url"></el-input>
                    <div class="form-tip">TV 包必填</div>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
@@ -399,10 +409,13 @@
                buildSubmitting: false,
                buildForm: {
                    buildType: 'release',
                    android_target: 'tv',
                    repoAlias: 'zy-monitor',
                    branch: 'master'
                    branch: 'master',
                    server_url: ''
                },
                buildRules: {
                    android_target: [{ required: true, message: '请选择目标类型', trigger: 'change' }],
                    repoAlias: [{ required: true, message: '请输入仓库别名', trigger: 'blur' }]
                },
@@ -419,6 +432,7 @@
            created() {
                this.loadData();
                this.buildForm.server_url = this.getServerUrl();
            },
            beforeDestroy() {
@@ -429,6 +443,10 @@
                // 获取请求头
                getHeaders() {
                    return { 'token': localStorage.getItem('token') };
                },
                getServerUrl() {
                    const { protocol, host } = window.location;
                    return `${protocol}//${host}/monitor`;
                },
                // 加载数据
@@ -590,8 +608,10 @@
                showBuildDialog() {
                    this.buildForm = {
                        buildType: 'release',
                        android_target: 'tv',
                        repoAlias: 'zy-monitor',
                        branch: 'master'
                        branch: 'master',
                        server_url: this.getServerUrl()
                    };
                    this.buildDialogVisible = true;
                },
@@ -638,21 +658,58 @@
                downloadApk(row) {
                    this.$set(row, 'downloading', true);
                    $.ajax({
                        url: baseUrl + '/apkBuildTask/download/' + row.id + '/auth',
                        url: baseUrl + '/apkBuildTask/downloadFile/' + row.id + '/auth',
                        headers: this.getHeaders(),
                        method: 'POST',
                        success: (res) => {
                        method: 'GET',
                        xhrFields: { responseType: 'blob' },
                        success: (data, status, xhr) => {
                            this.$set(row, 'downloading', false);
                            if (res.code === 200) {
                                this.$message.success('APK下载完成: ' + res.data.apkPath);
                                this.loadData();
                            } else {
                                this.$message.error(res.msg || '下载失败');
                            const contentType = xhr.getResponseHeader('Content-Type') || '';
                            if (contentType.indexOf('application/json') !== -1) {
                                const reader = new FileReader();
                                reader.onload = () => {
                                    try {
                                        const res = JSON.parse(reader.result);
                                        this.$message.error(res.msg || '下载失败');
                                    } catch (e) {
                                        this.$message.error('下载失败');
                                    }
                                };
                                reader.readAsText(data);
                                return;
                            }
                            const disposition = xhr.getResponseHeader('Content-Disposition') || '';
                            const fileNameMatch = disposition.match(/filename="?([^"]+)"?/);
                            let fileName = fileNameMatch ? decodeURIComponent(fileNameMatch[1]) : '';
                            if (!fileName) {
                                fileName = (row.projectName ? row.projectName : row.id) + '.apk';
                            }
                            const blob = new Blob([data], { type: contentType || 'application/octet-stream' });
                            const link = document.createElement('a');
                            link.href = URL.createObjectURL(blob);
                            link.download = fileName;
                            document.body.appendChild(link);
                            link.click();
                            document.body.removeChild(link);
                            URL.revokeObjectURL(link.href);
                            this.$message.success('APK已开始下载');
                        },
                        error: () => {
                        error: (xhr) => {
                            this.$set(row, 'downloading', false);
                            this.$message.error('请求失败');
                            if (xhr && xhr.response) {
                                const reader = new FileReader();
                                reader.onload = () => {
                                    try {
                                        const res = JSON.parse(reader.result);
                                        this.$message.error(res.msg || '下载失败');
                                    } catch (e) {
                                        this.$message.error('请求失败');
                                    }
                                };
                                reader.readAsText(xhr.response);
                            } else {
                                this.$message.error('请求失败');
                            }
                        }
                    });
                },
@@ -759,4 +816,4 @@
    </script>
</body>
</html>
</html>