preserve-order=true 无效的原因分析

本文介绍了如何使用TestNG控制测试类的执行顺序。通过不同配置方法对比,详细解释了当测试类包含@BeforeTest注解时,如何确保这些初始化操作与对应的测试方法按预期顺序执行。

       使用testNG suite测试的时候,如果一个<test>包含多个class,你又想指定执行的顺序,通常的做法是加入这样的属性<test name="testng_recharge3" preserve-order="true"> ,但是实际使用中要注意,如果你的class中包含有BeforeTest方法,就算你指定了preserve-order="true",BeforeTest方法一定是先执行的,等待所有的BeforeTest方法执行完毕才会执行@Test方法,至于其他的BeforeClass属性,我没试过,但是一样存在同样的问题,那么,如果你想每个Test和他配套的Before一起执行的话,就要在testNg.xml中设置成多个<test>标签,具体的代码和执行结果,如下所示:

test001.java

public class test001 {
    @BeforeTest
    public void initmodule() {
        System.out.println("进入到test001!");
    }
    @Test
    public void testng() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        System.out.println("this is test001");
    }

}

test002.java

public class test002 {
    @BeforeTest
    public void initmodule() {
        System.out.println("进入到test002!");
    }
    @Test
    public void testng() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        System.out.println("this is test002");
    }

}

test003.java

public class test003 {
    @BeforeTest
    public void initmodule() {
        System.out.println("进入到test003!");
    }
    @Test
    public void testng() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        System.out.println("this is test003");
    }

}


如果你配置成下面这个方式,注意,指定了preserve-order="true"

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >  
<suite name="fulltests">  
    <test name="testng_recharge" preserve-order="true">
        <classes>  
            <class name="com.test.shangfu.testsuite.test001" />  
            <class name="com.test.shangfu.testsuite.test002" />  
            <class name="com.test.shangfu.testsuite.test003" />  
        </classes>  
    </test>  
</suite>


那么执行结果是这样的:

进入到test001!
进入到test002!
进入到test003
this is test001
this is test002
this is test003

所有的@BeforeTest要先执行完毕才会去执行@Test

而如果你的testng.xml配置成下面这样:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >  
<suite name="tests">  
    <test name="testng_recharge1">
        <classes>  
            <class name="com.test.shangfu.testsuite.test001" />  
        </classes>  
    </test>  
        <test name="testng_recharge2">
        <classes>  
            <class name="com.test.shangfu.testsuite.test002" />  
        </classes>  
    </test>  
        <test name="testng_recharge3" >
        <classes>  
            <class name="com.test.shangfu.testsuite.test003" />  
        </classes>  
    </test>  

</suite>


那么执行结果是:

进入到test001!
this is test001
进入到test002!
this is test002
进入到test003

this is test003






Microsoft Windows [版本 10.0.26100.6899] (c) Microsoft Corporation。保留所有权利。 C:\Windows\System32>cd D:\MySQL5.7\bin 系统找不到指定的路径。 C:\Windows\System32>cd D:\MySQL5.7\binD:\software\mysql-5.7.24-winx64\bin 文件名、目录名或卷标语法不正确。 C:\Windows\System32>net start mysql 请求的服务已经启动。 请键入 NET HELPMSG 2182 以获得更多的帮助。 C:\Windows\System32>cd /d D:\software\mysql-5.7.24-winx64\bin D:\software\mysql-5.7.24-winx64\bin>mysql -u root -p # 回车后若提示输入密码,直接回车(空密码) mysql Ver 14.14 Distrib 5.7.24, for Win64 (x86_64) Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Usage: mysql [OPTIONS] [database] -?, --help Display this help and exit. -I, --help Synonym for -? --auto-rehash Enable automatic rehashing. One doesn't need to use 'rehash' to get table and field completion, but startup and reconnecting may take a longer time. Disable with --disable-auto-rehash. (Defaults to on; use --skip-auto-rehash to disable.) -A, --no-auto-rehash No automatic rehashing. One has to use 'rehash' to get table and field completion. This gives a quicker start of mysql and disables rehashing on reconnect. --auto-vertical-output Automatically switch to vertical output mode if the result is wider than the terminal width. -B, --batch Don't use history file. Disable interactive behavior. (Enables --silent.) --bind-address=name IP address to bind to. --binary-as-hex Print binary data as hex --character-sets-dir=name Directory for character set files. --column-type-info Display column type information. -c, --comments Preserve comments. Send comments to the server. The default is --skip-comments (discard comments), enable with --comments. -C, --compress Use compression in server/client protocol. -#, --debug[=#] This is a non-debug version. Catch this and exit. --debug-check This is a non-debug version. Catch this and exit. -T, --debug-info This is a non-debug version. Catch this and exit. -D, --database=name Database to use. --default-character-set=name Set the default character set. --delimiter=name Delimiter to be used. --enable-cleartext-plugin Enable/disable the clear text authentication plugin. -e, --execute=name Execute command and quit. (Disables --force and history file.) -E, --vertical Print the output of a query (rows) vertically. -f, --force Continue even if we get an SQL error. --histignore=name A colon-separated list of patterns to keep statements from getting logged into syslog and mysql history. -G, --named-commands Enable named commands. Named commands mean this program's internal commands; see mysql> help . When enabled, the named commands can be used from any line of the query, otherwise only from the first line, before an enter. Disable with --disable-named-commands. This option is disabled by default. -i, --ignore-spaces Ignore space after function names. --init-command=name SQL Command to execute when connecting to MySQL server. Will automatically be re-executed when reconnecting. --local-infile Enable/disable LOAD DATA LOCAL INFILE. -b, --no-beep Turn off beep on error. -h, --host=name Connect to host. -H, --html Produce HTML output. -X, --xml Produce XML output. --line-numbers Write line numbers for errors. (Defaults to on; use --skip-line-numbers to disable.) -L, --skip-line-numbers Don't write line number for errors. -n, --unbuffered Flush buffer after each query. --column-names Write column names in results. (Defaults to on; use --skip-column-names to disable.) -N, --skip-column-names Don't write column names in results. --sigint-ignore Ignore SIGINT (CTRL-C). -o, --one-database Ignore statements except those that occur while the default database is the one named at the command line. -p, --password[=name] Password to use when connecting to server. If password is not given it's asked from the tty. -W, --pipe Use named pipes to connect to server. -P, --port=# Port number to use for connection or 0 for default to, in order of preference, my.cnf, $MYSQL_TCP_PORT, /etc/services, built-in default (3306). --prompt=name Set the mysql prompt to this value. --protocol=name The protocol to use for connection (tcp, socket, pipe, memory). -q, --quick Don't cache result, print it row by row. This may slow down the server if the output is suspended. Doesn't use history file. -r, --raw Write fields without conversion. Used with --batch. --reconnect Reconnect if the connection is lost. Disable with --disable-reconnect. This option is enabled by default. (Defaults to on; use --skip-reconnect to disable.) -s, --silent Be more silent. Print results with a tab as separator, each row on new line. --shared-memory-base-name=name Base name of shared memory. -S, --socket=name The socket file to use for connection. --ssl-mode=name SSL connection mode. --ssl Deprecated. Use --ssl-mode instead. (Defaults to on; use --skip-ssl to disable.) --ssl-verify-server-cert Deprecated. Use --ssl-mode=VERIFY_IDENTITY instead. --ssl-ca=name CA file in PEM format. --ssl-capath=name CA directory. --ssl-cert=name X509 cert in PEM format. --ssl-cipher=name SSL cipher to use. --ssl-key=name X509 key in PEM format. --ssl-crl=name Certificate revocation list. --ssl-crlpath=name Certificate revocation list path. --tls-version=name TLS version to use, permitted values are: TLSv1, TLSv1.1 -t, --table Output in table format. --tee=name Append everything into outfile. See interactive help (\h) also. Does not work in batch mode. Disable with --disable-tee. This option is disabled by default. -u, --user=name User for login if not current user. -U, --safe-updates Only allow UPDATE and DELETE that uses keys. -U, --i-am-a-dummy Synonym for option --safe-updates, -U. -v, --verbose Write more. (-v -v -v gives the table output format). -V, --version Output version information and exit. -w, --wait Wait and retry if connection is down. --connect-timeout=# Number of seconds before connection timeout. --max-allowed-packet=# The maximum packet length to send to or receive from server. --net-buffer-length=# The buffer size for TCP/IP and socket communication. --select-limit=# Automatic limit for SELECT when using --safe-updates. --max-join-size=# Automatic limit for rows in a join when using --safe-updates. --secure-auth Refuse client connecting to server if it uses old (pre-4.1.1) protocol. Deprecated. Always TRUE --server-arg=name Send embedded server this as a parameter. --show-warnings Show warnings after every statement. -j, --syslog Log filtered interactive commands to syslog. Filtering of commands depends on the patterns supplied via histignore option besides the default patterns. --plugin-dir=name Directory for client-side plugins. --default-auth=name Default authentication client-side plugin to use. --binary-mode By default, ASCII '\0' is disallowed and '\r\n' is translated to '\n'. This switch turns off both features, and also turns off parsing of all clientcommands except \C and DELIMITER, in non-interactive mode (for input piped to mysql or loaded using the 'source' command). This is necessary when processing output from mysqlbinlog that may contain blobs. --connect-expired-password Notify the server that this client is prepared to handle expired password sandbox mode. Default options are read from the following files in the given order: C:\Windows\my.ini C:\Windows\my.cnf C:\my.ini C:\my.cnf D:\software\mysql-5.7.24-winx64\my.ini D:\software\mysql-5.7.24-winx64\my.cnf D:\software\mysql-5.7.24-winx64\mysql-5.7.24-winx64\my.ini D:\software\mysql-5.7.24-winx64\mysql-5.7.24-winx64\my.cnf The following groups are read: mysql client The following options may be given as the first argument: --print-defaults Print the program argument list and exit. --no-defaults Don't read default options from any option file, except for login file. --defaults-file=# Only read default options from the given file #. --defaults-extra-file=# Read this file after the global files are read. --defaults-group-suffix=# Also read groups with concat(group, suffix) --login-path=# Read this path from the login file. Variables (--variable-name=value) and boolean options {FALSE|TRUE} Value (after reading options) --------------------------------- ---------------------------------------- auto-rehash TRUE auto-vertical-output FALSE bind-address (No default value) binary-as-hex FALSE character-sets-dir (No default value) column-type-info FALSE comments FALSE compress FALSE database (No default value) default-character-set utf8 delimiter ; enable-cleartext-plugin FALSE vertical FALSE force FALSE histignore (No default value) named-commands FALSE ignore-spaces FALSE init-command (No default value) local-infile FALSE no-beep FALSE host (No default value) html FALSE xml FALSE line-numbers TRUE unbuffered FALSE column-names TRUE sigint-ignore FALSE port 0 prompt mysql> quick FALSE raw FALSE reconnect TRUE shared-memory-base-name (No default value) socket (No default value) ssl TRUE ssl-verify-server-cert FALSE ssl-ca (No default value) ssl-capath (No default value) ssl-cert (No default value) ssl-cipher (No default value) ssl-key (No default value) ssl-crl (No default value) ssl-crlpath (No default value) tls-version (No default value) table FALSE user root safe-updates FALSE i-am-a-dummy FALSE connect-timeout 0 max-allowed-packet 16777216 net-buffer-length 16384 select-limit 1000 max-join-size 1000000 secure-auth TRUE show-warnings FALSE plugin-dir (No default value) default-auth (No default value) binary-mode FALSE connect-expired-password FALSE D:\software\mysql-5.7.24-winx64\bin>
最新发布
12-20
以下代码生成的pd文件fwindows预览有显示文字,用Adobe打开时不显示 import pikepdf from pikepdf import Name, Dictionary import os vector_pdf_path = "G:/compass/imageConvert/image/images/c/aaa.pdf" output_pdf_path = "G:/compass/imageConvert/image/images/c/aaa_modified.pdf" # 新的输出路径 def convertPdf(vector_pdf_path, output_pdf_path): # 打开原始PDF文件 pdf = pikepdf.open(vector_pdf_path, allow_overwriting_input=True) page = pdf.pages[0] # 创建OCG (Optional Content Group) 图层 ocg_dict = pikepdf.Dictionary({ '/Type': pikepdf.Name('/OCG'), '/Name': 'MyLayer', '/Intent': pikepdf.Name('/View') }) ocg = pdf.make_indirect(ocg_dict) # 添加图层属性,确保图层的可见性 pdf.Root['/OCProperties'] = { '/OCGs': [ocg], # 只添加这个图层 '/D': { '/Order': [ocg], # 图层顺序 '/OFF': [], # 默认关闭 '/AS': [ocg], # 图层显示 '/RBGroups': [], '/Locked': [] } } try: # 创建文本流 # 使用内的 Helvetica 字体,确保文本能正确显示 new_content_stream_bytes = ( b"q\n" # 保存图层状态 b"/F1 12 Tf 100 700 Td (Hello, Layer!) Tj\n" # 设字体、大小和文本内容 b"Q\n" # 恢复图层状态 ) # 将新的内容流包裹在图层控制的标记中 wrapped_stream_bytes = ( b"q\n" # 保存图层状态 b"/OC " + str(ocg).encode('utf-8') + b" BDC\n" # 设图层 + new_content_stream_bytes # 新的文本内容流 + b"\nEMC\n" # 结束图层区域 + b"Q\n" # 恢复图层状态 ) # 创建新的内容流,包含新文本内容 wrapped_stream = pikepdf.Stream(pdf, wrapped_stream_bytes) # 替换页面中的内容流,完全用新的内容流替代 page[Name('/Contents')] = wrapped_stream # 保存到新的PDF文件 if os.path.exists(output_pdf_path): os.remove(output_pdf_path) # 如果文件存在,先删除 pdf.save(output_pdf_path) print(f"PDF 保存成功:{output_pdf_path}") except Exception as e: print("PDF 内容流处理失败:") print(f"错误信息: {str(e)}") # 调用函数,将结果保存到新的PDF文件 convertPdf(vector_pdf_path, output_pdf_path)
11-13
% 主程序:碳化硅外延层厚度计算与可靠性分析 % 功能:读取附件1和附件2的数据,按问题二模型求解步骤计算厚度并分析可靠性 %% 1. 读取数据文件 % 读取附件1(入射角10°) data1 = readtable('附件1.xlsx', 'VariableNamingRule', 'preserve'); sigma1 = data1.('波数 (cm⁻¹)'); % 波数序列(cm⁻¹) R1_raw = data1.('反射率 (%)'); % 原始反射率序列(%) % 读取附件2(入射角15°) data2 = readtable('附件2.xlsx', 'VariableNamingRule', 'preserve'); sigma2 = data2.('波数 (cm⁻¹)'); % 波数序列(cm⁻¹) R2_raw = data2.('反射率 (%)'); % 原始反射率序列(%) %% 2. 设模型参数 theta0_1 = 10; % 附件1入射角(度) theta0_2 = 15; % 附件2入射角(度) n1 = 2.65; % 碳化硅外延层折射率(常数) n2 = 2.68; % 碳化硅衬底折射率(常数,n2>n1) %% 3. 反射率预处理(截断异常值) R1_processed = preprocess_reflectance(R1_raw, sigma1, true); % 附件1预处理(标识为附件1) R2_processed = preprocess_reflectance(R2_raw, sigma2, false); % 附件2预处理(标识为非附件1) %% 4. 反射率平滑(5点移动平均) R1_smoothed = smooth_reflectance(R1_processed); % 附件1平滑后反射率 R2_smoothed = smooth_reflectance(R2_processed); % 附件2平滑后反射率 %% 5. 识别有效干涉极值点 valid_sigma1 = find_extrema(R1_smoothed, sigma1); % 附件1有效极值波数 valid_sigma2 = find_extrema(R2_smoothed, sigma2); % 附件2有效极值波数 %% 6. 计算波数差统计量 [mean_ds1, std_ds1] = calculate_wavenumber_stats(valid_sigma1); % 附件1波数差统计 [mean_ds2, std_ds2] = calculate_wavenumber_stats(valid_sigma2); % 附件2波数差统计 %% 7. 计算外延层厚度及标准差 [d1, s_d1] = calculate_thickness(mean_ds1, std_ds1, theta0_1, n1); % 附件1厚度 [d2, s_d2] = calculate_thickness(mean_ds2, std_ds2, theta0_2, n1); % 附件2厚度 %% 8. 可靠性分析 K1 = length(valid_sigma1); % 附件1有效极值点数量 K2 = length(valid_sigma2); % 附件2有效极值点数量 [valid_count, stable_cv, consistent_re, valid_assumption] = ... reliability_analysis(d1, d2, s_d1, s_d2, K1, K2, mean_ds1, std_ds1, mean_ds2, std_ds2, n1, n2); %% 9. 输出结果 fprintf('===================================== '); fprintf('=== 附件1(入射角10°)计算结果 === '); fprintf('有效极值点数量:%d ', K1); fprintf('平均波数差:%.4f cm⁻¹ ', mean_ds1); fprintf('波数差标准差:%.4f cm⁻¹ ', std_ds1); fprintf('外延层厚度:%.4f cm(%.2f μm) ', d1, d1*1e4); % 1cm=1e4μm fprintf('厚度标准差:%.4f cm(%.2f μm) ', s_d1, s_d1*1e4); fprintf(' === 附件2(入射角15°)计算结果 === '); fprintf('有效极值点数量:%d ', K2); fprintf('平均波数差:%.4f cm⁻¹ ', mean_ds2); fprintf('波数差标准差:%.4f cm⁻¹ ', std_ds2); fprintf('外延层厚度:%.4f cm(%.2f μm) ', d2, d2*1e4); fprintf('厚度标准差:%.4f cm(%.2f μm) ', s_d2, s_d2*1e4); fprintf(' === 可靠性分析结果 === '); fprintf('极值点数量有效性:%s ', valid_count ? '有效(≥5个)' : '无效(<5个)'); fprintf('波数差稳定性:%s(CV1=%.2f%%, CV2=%.2f%%) ', ... stable_cv ? '稳定(<5%)' : '不稳定(≥5%)', ... std_ds1/mean_ds1*100, std_ds2/mean_ds2*100); fprintf('结果一致性:%s(相对误差=%.2f%%) ', ... consistent_re < 10 ? '一致(<10%)' : '不一致(≥10%)', consistent_re); fprintf('模型假设合理性:%s(n2=%.2f > n1=%.2f) ', ... valid_assumption ? '合理' : '不合理', n2, n1); fprintf('===================================== '); % ------------------------------------------------------------------------------ function R_processed = preprocess_reflectance(R_raw, sigma, is_attachment1) % 反射率异常值预处理:附件1截断波数795~805 cm⁻¹超过100%的点,所有点截断至0~100% % 输入:R_raw - 原始反射率序列;sigma - 对应波数序列;is_attachment1 - 是否为附件1(逻辑值) % 输出:R_processed - 预处理后反射率序列 % 初始化处理后的反射率 R_processed = R_raw; % 仅针对附件1的特定波数范围(795~805 cm⁻¹)截断超过100%的点 if is_attachment1 idx_795_805 = (sigma >= 795) & (sigma <= 805); R_processed(idx_795_805) = min(R_processed(idx_795_805), 100); end % 所有点截断至0~100%的物理范围 R_processed = max(min(R_processed, 100), 0); end % ------------------------------------------------------------------------------ function R_smoothed = smooth_reflectance(R_processed) % 5点移动平均平滑:处理边缘点(前2点/后2点用缩短窗口) % 输入:R_processed - 预处理后反射率序列 % 输出:R_smoothed - 平滑后反射率序列 N = length(R_processed); R_smoothed = zeros(size(R_processed)); for i = 1:N if i == 1 % 第1点:前3点平均 R_smoothed(i) = mean(R_processed(1:min(3, N))); elseif i == 2 % 第2点:前4点平均 R_smoothed(i) = mean(R_processed(1:min(4, N))); elseif i == N-1 % 倒数第2点:后4点平均 R_smoothed(i) = mean(R_processed(max(1, N-3):N)); elseif i == N % 最后1点:后3点平均 R_smoothed(i) = mean(R_processed(max(1, N-2):N)); else % 中间点:5点移动平均(i-2到i+2) R_smoothed(i) = mean(R_processed(i-2:i+2)); end end end % ------------------------------------------------------------------------------ function valid_sigma = find_extrema(R_smoothed, sigma) % 干涉极值点识别:一阶/二阶差分法提取极值,筛选有效点(剔除波数差异常值) % 输入:R_smoothed - 平滑后反射率;sigma - 波数序列 % 输出:valid_sigma - 有效极值点波数序列 N = length(R_smoothed); if N < 3 valid_sigma = []; return; end % 计算一阶差分(R(i+1)-R(i))和二阶差分(delta_R(i+1)-delta_R(i)) delta_R = diff(R_smoothed); % 一阶差分,长度N-1 delta2_R = diff(delta_R); % 二阶差分,长度N-2 % 提取极大值点(前升后降+上凸)和极小值点(前降后升+下凸) max_idx = []; min_idx = []; for i = 2:N-1 % 原序列索引(避开边缘点) if delta_R(i-1) > 0 && delta_R(i) < 0 && delta2_R(i-1) < 0 max_idx = [max_idx, i]; % 极大值点索引 end if delta_R(i-1) < 0 && delta_R(i) > 0 && delta2_R(i-1) > 0 min_idx = [min_idx, i]; % 极小值点索引 end end % 合并并排序极值点(按波数递增) extrema_idx = sort([max_idx; min_idx]); if isempty(extrema_idx) valid_sigma = []; return; end % 计算相邻波数差,筛选偏差≤2σ的点 extrema_sigma = sigma(extrema_idx); delta_sigma = diff(extrema_sigma); mean_ds = mean(delta_sigma); std_ds = std(delta_sigma); valid_ds = abs(delta_sigma - mean_ds) <= 2*std_ds; % 保留连续有效点(直到最后一个有效差) if any(valid_ds) last_valid = find(valid_ds, 1, 'last'); valid_extrema_idx = extrema_idx(1:last_valid+1); else valid_extrema_idx = []; end % 输出有效极值点(确保≥5个) valid_sigma = sigma(valid_extrema_idx); if length(valid_sigma) < 5 valid_sigma = []; end end % ------------------------------------------------------------------------------ function [mean_ds, std_ds] = calculate_wavenumber_stats(valid_sigma) % 波数差统计:计算有效极值点的平均波数差和标准差 % 输入:valid_sigma - 有效极值点波数序列 % 输出:mean_ds - 平均波数差;std_ds - 波数差标准差 K = length(valid_sigma); if K < 2 mean_ds = NaN; std_ds = NaN; return; end delta_sigma = diff(valid_sigma); % 相邻波数差 mean_ds = mean(delta_sigma); % 平均波数差 std_ds = std(delta_sigma); % 波数差样本标准差(除以n-1) end % ------------------------------------------------------------------------------ function [d, s_d] = calculate_thickness(mean_ds, std_ds, theta0, n1) % 厚度计算:根据平均波数差和模型参数计算厚度及标准差 % 输入:mean_ds - 平均波数差;std_ds - 波数差标准差;theta0 - 入射角(度);n1 - 外延层折射率 % 输出:d - 外延层厚度(cm);s_d - 厚度标准差(cm) % 计算折射角余弦(斯涅尔定律) sin_theta0 = sind(theta0); % 入射角正弦(度转正弦) sin_theta1 = sin_theta0 / n1; % 外延层内折射角正弦 cos_theta1 = sqrt(1 - sin_theta1^2); % 折射角余弦 % 厚度公式(问题二核心公式) d = 1 / (2 * n1 * cos_theta1 * mean_ds); % 误差传递:相对误差等于波数差相对误差 if mean_ds ~= 0 s_d = d * (std_ds / mean_ds); else s_d = NaN; end end % ------------------------------------------------------------------------------ function [valid_count, stable_cv, consistent_re, valid_assumption] = ... reliability_analysis(d1, d2, s_d1, s_d2, K1, K2, mean_ds1, std_ds1, mean_ds2, std_ds2, n1, n2) % 可靠性分析:验证极值点数量、波数差稳定性、结果一致性、模型假设 % 输入:d1/d2 - 厚度;s_d1/s_d2 - 厚度标准差;K1/K2 - 极值点数量;mean_ds/std_ds - 波数差统计;n1/n2 - 折射率 % 输出:各可靠性指标布尔值 % 1. 极值点数量有效性(≥5个) valid_count = (K1 >= 5) && (K2 >= 5); % 2. 波数差稳定性(变异系数CV<5%) cv1 = (std_ds1 / mean_ds1) * 100; % 附件1变异系数 cv2 = (std_ds2 / mean_ds2) * 100; % 附件2变异系数 stable_cv = (cv1 < 5) && (cv2 < 5); % 3. 结果一致性(相对误差RE<10%) consistent_re = abs(d1 - d2) / ((d1 + d2)/2) * 100; % 4. 模型假设合理性(n2>n1) valid_assumption = (n2 > n1); end 帮我检查所有错误并改正,输出改正后的完整代码
09-08
<template> <view> <view style="position: relative;"> <!-- banner --> <view class="container"> <swiper class="view_banner" :indicator-dots="true" autoplay interval="5000" duration="500" circular="true" previous-margin="20px" next-margin="20px"> <swiper-item v-for="(item, index) in bannerItem" :key="index" style="margin-top: 5%;"> <view class="swiper_banner" @click="bannerClik(item)"> <image :src="item.fileImg" mode="aspectFill"></image> </view> </swiper-item> </swiper> </view> <!-- banner下功能按钮 --> <view class="function-btn"> <view class="btn-history" @click="bindHistory()"> <image class="btn-image" src="@/static/images/index/我的追剧.png" mode="aspectFit"></image> <view class="btn-text">我的追剧</view> </view> <view class="btn-history" @click="bindSort()"> <image class="btn-image" src="@/static/images/index/排行榜.png" mode="aspectFit"></image> <view class="btn-text">排行榜</view> </view> <view class="btn-history" @click="fulllist()"> <image class="btn-image" src="@/static/images/index/短剧-copy-copy.png" mode="aspectFill"></image> <view class="btn-text">完整短剧</view> </view> <view class="btn-history" @click="freelist()"> <image class="btn-image" src="@/static/images/index/free.png" mode="aspectFill"></image> <view class="btn-text">免费短剧</view> </view> </view> <view class="gradient-background"> <view style="display: flex; align-items: center;"> <view class="view-desc" style="margin-top: 20px; margin-bottom: -4px;"> <image src="@/static/images/index/toplist.png" mode="scaleToFill"></image> 短剧排行 <text style="font-size: 14px; font-weight: normal; position: absolute; right: 0; margin-right: 12px;" @click="bindSort()"> 完整榜单> </text> </view> </view> <view v-for="(item, index) in hotVideoItem" v-if="index < 3" style="border-radius: 8px; background-color: white; margin: 15px; height: 200px;"> <view style="display: flex; width: 100%;"> <image :src="item.picUrl" style="width: 50%; height: 200px; border-radius: 8px 0px 0px 8px"></image> <view class="video-number" style="left: 0; position: absolute; margin-left: 15px; font-weight: bold;">TOP {{ index + 1 }}</view> <view style="flex-direction: column; margin: 20px; width: 50%;"> <view style="font-size: 16px;"> {{ item.name }} </view> <view style="color: #a1a0a0; font-size: 14px; margin-top: 6px;"> 全{{ item.totalVideo }}集 </view> <view style="color: #a1a0a0; margin-top: 4px;"> <image src="@/static/images/index/播放量.png" style="width: 18px; height: 12px;" mode="scaleToFill"></image> <text style="font-size: 14px; margin-left: 2%;">{{ formatPlays(item.plays) }}</text> </view> <view style="display: flex; font-size: 16px; margin-top: 30px;"> <view @click="videoPlay(item)" style="border-radius: 50px; height: 35px; width: 115px; text-align: center; color: white; display: flex; border: 1px solid #3d8aff; justify-content: center; align-items: center;" class="text-container"> <image src="@/static/images/index/play.png" mode="scaleToFill" style="height: 50%; width: 20%;"></image> <text style="margin-left: 2%; font-size: 12px;">立即观看</text> </view> <view v-if="item.state == 'NO' || item.state == null" @click="changeChase(item, index)" style="border-radius: 50px; height: 35px; width: 115px; text-align: center; background-color: white; display: flex; margin-left: 8%; color: #3d8aff; border: 1px solid #3d8aff; justify-content: center; align-items: center;"> <image src="@/static/images/index/收藏.png" mode="scaleToFill" style="height: 40%; width: 20%;"></image> <text style="margin-left: 2%; font-size: 12px;">加入追剧</text> </view> <view v-else @click="changeChase(item, index)" style="border-radius: 50px; height: 35px; width: 115px; text-align: center; background-color: white; display: flex; margin-left: 8%; color: #3d8aff; border: 1px solid #3d8aff; justify-content: center; align-items: center;"> <image src="@/static/images/index/收藏后.png" mode="scaleToFill" style="height: 50%; width: 25%;"></image> <text style="margin-left: 2%; font-size: 12px;">已追剧</text> </view> </view> </view> </view> </view> </view> <view style="color: dimgray; font-weight: bold; font-size: 15px; display: flex; overflow-x: scroll; justify-content: flex-start; margin-top: 20px; margin-left: 20px; margin-right: 20px;"> <view style="white-space: nowrap;" key="'0'" :class="{ 'selected-text': selectedTagId == '0' }"> <text @click="getHomeVideo()">全部</text> </view> <view v-for="(item, index) in tagList" :key="item.id" style="white-space: nowrap; margin-left: 20px;" :class="{ 'selected-text': selectedTagId == item.id }"> <text @click="getSortVideo(item)">{{ item.tag }}</text> </view> </view> <view class="container-video" v-if="selectedTagId == '0'"> <view class="video-list" v-for="(item, index) in videoItem" :key="index"> <view class="video-item" @click="videoPlay(item)"> <image :src="item.picUrl" mode="scaleToFill" style="border-radius: 8px 8px 0px 0px;"></image> <text style="margin-top: 2%;">{{ item.name }}</text> <text style="font-size: 14px; color: #a1a0a0;">全{{ item.totalVideo }}集</text> <view style="color: #a1a0a0; display: flex; margin-left: 3%;"> <image src="@/static/images/index/播放量.png" style="width: 18px; height: 12px; margin-top: 4%;" mode="scaleToFill"></image> <text style="font-size: 14px; margin-left: 2%; color: #a1a0a0;"> {{ formatPlays(item.plays) }} </text> </view> </view> </view> </view> <view class="end-style" v-if="historyList.length > 0 && showHistoryList"> <view class="collapsible-view" @click="toPlay()"> <view class="close-button" @click.stop="toggleHistoryList">×</view> <image :src="historyList[0].picUrl" style="width: 25%; height: 100%; border-radius: 5px 0px 0px 5px;"></image> <view style="display: grid; margin-left: 10px;"> <text style="font-size: 14px; margin-top: 8%;">{{ historyList[0].seriesName }}</text> <view style="display: flex; margin-top: -2%;"> <text style="font-size: 14px;">上次看到第{{ historyList[0].videoName }}集</text> <view @click="toPlay()" style="border-radius: 50px; height: 30px; width: 80px; color: white; display: flex; border: 1px solid #3d8aff; justify-content: center; align-items: center; margin-top: 5%; margin-left: 60px;" class="text-container"> <text style="font-size: 14px;">立即观看</text> </view> </view> </view> </view> </view> </view> </view> </template> <script> import BASE_URL from '@/components/baseUrl'; import request from "@/components/request.js" // const PlayerManager = require('@/pages/utils/playerManager.js') // 注释掉这一行 export default { data() { return { videoItem: [], bannerItem: [], page: 1, hotVideoItem: [], videoName: "", sortHotItem: [], sortHighItem: [], sortNewItem: [], searchPlaceholder: "输入短剧名称", isNew: false, has: true, historyList: [], linkId: "", mediaId: "", seriesId: "", seriesName: "", platform: "", adId: "", adAccount: "", total: 0, tagList: [], selectedTagId: '0', sortItem: [], showHistoryList: true, // 控制历史记录折叠视图的显示与隐藏 } }, onLoad: function(options) { var that = this; console.log("loading...", uni.getStorageSync("option")); console.log("some field:", options); console.log(BASE_URL); this.linkId = options.Lid; this.seriesId = options.videoId; this.mediaId = options.mediaId; this.seriesName = options.videoName; if (this.linkId != undefined && this.mediaId == undefined) { if (!uni.getStorageSync("userInfo")) { this.getSeriesByLink(this.linkId); } } if (options.adv_id) { this.adId = options.adv_id; this.platforms = "DOUYIN"; this.adAccount = options.advertiser_id; const query = { adId: this.adAccount, platform: this.platforms, clickId: options.clue_token, exposureId: options.exposure_id, callback: null, }; uni.setStorageSync("option", query); } this.getIndex(); uni.request({ url: BASE_URL + "/program/page", method: "POST", data: { current: 1, name: "合恕小剧场", size: 10, type: "", }, header: { "Content-Type": "application/json", }, success: (res) => { console.log("请求成功:", res); if (res.data.data.records.length > 0) { uni.setStorageSync("programId", res.data.data.records[0].id); uni.setStorageSync("program", res.data.data.records[0]); uni.setStorageSync("pay", res.data.data.records[0]); if (uni.getStorageSync("userInfo")) { // 如果用户已登录,执行相关操作 console.log("用户已登录"); if ( this.seriesName != undefined && this.seriesId != undefined && this.linkId != undefined && this.mediaId != undefined ) { console.log("存在系列名称、系列 ID、链接 ID 和媒体 ID,调用 getDramaVideo 方法"); this.getDramaVideo(uni.getStorageSync("userInfo").isVip); } else { console.log("媒体 ID 不存在,发起请求获取相关数据"); if (this.linkId != undefined && this.mediaId == undefined) { uni.request({ url: BASE_URL + "/biz/link/queryByLink", method: "GET", header: { "token": uni.getStorageSync("token"), "programId": uni.getStorageSync("programId"), }, data: { link: this.linkId, }, success: (res) => { console.log("请求链接相关数据成功"); this.seriesId = res.data.data.seriesId; this.mediaId = res.data.data.mediaId; this.seriesName = res.data.data.seriesName; if ( this.seriesName != undefined && this.seriesId != undefined && this.linkId != undefined && this.mediaId != undefined ) { console.log("成功获取系列名称、系列 ID、链接 ID 和媒体 ID,调用 getDramaVideo 方法"); this.getDramaVideo(uni.getStorageSync("userInfo").isVip); } }, fail: (err) => { console.error("请求链接相关数据失败:", err); } }); } } console.log("获取用户信息及其他页面数据"); this.getUserInfo(); this.queryDict(); this.getHistory(); this.getBanner(); this.getHomeVideo(); this.getSortList(); this.getRecommend(); } else { // 如果用户未登录,调用抖音登录接口 console.log("用户未登录,调用抖音登录接口"); tt.login({ success(res) { console.log("抖音登录成功,返回结果:", res); if (res.code) { console.log("获取到有效的 code:", res.code); uni.request({ url: BASE_URL + "/auth/b/getOpenid", header: { "programId": uni.getStorageSync("programId"), }, method: "GET", data: { code: res.code, programType: "DOUYIN", }, success: (res) => { console.log("请求获取 OpenID 成功,返回结果:", res); if (res.data.code === 200) { console.log("成功获取 OpenID,调用 loginFirst 方法进行登录"); that.loginFirst(res.data.data); } else { console.error("获取 OpenID 失败,错误信息:", res); } }, fail: (err) => { console.error("请求获取 OpenID 失败,错误信息:", err); }, }); } else { console.error("未获取到有效的 code,抖音登录失败"); } }, fail(err) { console.error("抖音登录失败,错误信息:", err); }, }); } } }, fail: (err) => { console.error("请求失败:", err); }, }); this.getSortTag(); this.isNew = getApp().globalData.isNew; }, onPullDownRefresh() { // this.getHistory() this.getBanner() // this.page = 1 // this.getHomeVideo() }, onShow() { this.getHistory() this.getSortList() }, methods: { formatPlays(plays) { if (plays < 10000) { return `${plays}次`; // 不足1万,直接显示数字 } else { return `${(plays / 10000).toFixed(2)}万`; // 超过1万,显示为X.XX万 } }, toggleHistoryList(event) { this.showHistoryList = !this.showHistoryList; // 切换显示与隐藏 }, bindSign() { uni.navigateTo({ url: "/packagesUser/sign/sign" }) }, bindSort() { uni.navigateTo({ url: "/packagesVideo/videoSort/videoSort" }) }, bindHistory() { uni.navigateTo({ url: "/pages/chase/chase" }) }, loginFirst(phoneNumber) { console.log("loginFirst called with phoneNumber:", phoneNumber); // 加载加密库 const sm2 = require("sm-crypto").sm2; const cipherMode = 0; // 加密用户输入的密码(假设用户输入的密码存储在 this.userPassword 中) const encryptedPassword = sm2.doEncrypt("123456", "03c0e7c1d3d5c33325ee5abc68a8c37dddeab3d2d2b90fde0cfaa78315b8e87f68", cipherMode); // 显示加载提示 uni.showLoading({ title: "正在登录", }); uni.request({ url: BASE_URL + "/auth/b/loginOrCreat", method: "POST", header: { "programId": uni.getStorageSync("programId"), "content-type": "application/json; charset=utf-8;", }, data: { account: phoneNumber, password: encryptedPassword, platform: 2, // 抖音平台标识 adId: uni.getStorageSync("option").adId, adAccount: this.adAccount, invest: { exposureId: uni.getStorageSync("option").exposureId, eventType: 0, platform: uni.getStorageSync("option").platform, fee: 0, clickId: uni.getStorageSync("option").clickId, code: uni.getStorageSync("douyinCode"), adId: uni.getStorageSync("option").adId, callback: uni.getStorageSync("option").callback, }, }, success: (res) => { uni.hideLoading(); console.log("loginOrCreat response:", res); if (res.data && res.data.code === 200) { uni.setStorageSync("token", res.data.data.token); uni.setStorageSync("userInfo", res.data.data.user); this.getUserInfo(); uni.showToast({ title: "登录成功", icon: "success", }); } else { console.error("loginOrCreat failed", res); uni.showToast({ title: "登录失败,请重试", icon: "none", }); } }, fail: (err) => { uni.hideLoading(); console.error("loginOrCreat failed", err); uni.showToast({ title: "网络请求失败,请检查网络", icon: "none", }); }, }); }, getDramaVideo(param) { uni.request({ url: BASE_URL + '/biz/series/detail', method: 'GET', data: { id: this.seriesId }, success: (res) => { if (res.data.code == 200) { // 注释掉与 PlayerManager 相关的代码 // if (param != null && param == "YES") { // PlayerManager.navigateToPlayer(res.data.data.mediaId, res.data.data.start - 1, // res.data.data.totalVideo, currentseries) // } else if (res.data.data.isPay == "NO") { // PlayerManager.navigateToPlayer(res.data.data.mediaId, res.data.data.totalVideo, // res.data.data.totalVideo, currentseries) // } else { // const currentseries = res.data.data // uni.request({ // url: BASE_URL + "/biz/order/getExpendByUser", // method: 'POST', // header: { // token: uni.getStorageSync("token") // }, // data: { // seriesName: this.seriesName, // userId: uni.getStorageSync("userInfo").id, // seriesId: this.seriesId // }, // success: (res) => { // if (res.data.code == 200) { // const len = res.data.data.length // PlayerManager.navigateToPlayer(currentseries.mediaId, // currentseries.start - 1, 0, currentseries, len) // if (len > 0) { // uni.setStorageSync("haveVideo", res.data.data) // } // } // } // }) // } } }, }) }, getUserInfo() { var that = this; console.log("当前 token:", uni.getStorageSync("token")); uni.request({ url: BASE_URL + "/biz/user/getLoginUserByToken", method: "GET", header: { "token": uni.getStorageSync("token"), "programId": uni.getStorageSync("programId"), }, data: { link: this.linkId, }, success: (res) => { console.log("getLoginUserByToken response:", res); // 检查后端返回的数据是否包含用户信息 if (res.data && res.data.id) { // 如果后端直接返回用户信息 uni.setStorageSync("userInfo", res.data); this.userInfo = uni.getStorageSync("userInfo"); } else if (res.data && res.data.code === 401) { // 处理 token 无效的情况 console.error("Token无效,重新登录"); this.loginFirst(); } else { // 如果返回的数据不符合预期,抛出错误 console.error("getLoginUserByToken failed", res); } }, fail: (err) => { console.error("request failed", err); } }); }, freelist() { uni.navigateTo({ url: '/pages/freelist/freelist' }) }, changeChase(item, index) { uni.showLoading({ title:"加载中..." }) var that = this var state = "" if (item.state == "YES") { state = "NO" } else { state = "YES" } uni.request({ url: BASE_URL + "/chase/addOrCancel", method:'POST', header:{ token: uni.getStorageSync("token") }, data: { userId: uni.getStorageSync("userInfo").id, seriesId: item.id, state: state }, success: (res) => { uni.hideLoading() that.hotVideoItem[index].state = state if (uni.getStorageSync("userInfo").chase == 0 && state == "YES") { const user = uni.getStorageSync("userInfo") user.chase = 1 uni.setStorageSync("userInfo", user) this.userInfo = uni.getStorageSync("userInfo") uni.showToast({ title: '恭喜获得30金豆', image: '/static/images/index/bean.png' }) } },fail: () => { uni.hideLoading() uni.showToast({ title:'请求失败,请稍后再试~', icon: 'none' }) } }) }, fulllist() { uni.navigateTo({ url: '/pages/fulllist/fulllist' }) }, getBanner() { let data = { current: 1, size: 20 } uni.request({ url: BASE_URL + "/biz/banner/page", method: "GET", header: { "programId": uni.getStorageSync("programId"), 'content-type': 'application/json; charset=utf-8;', }, data: { current: 1, size: 20 }, success: (res) => { if (res.data.code == 200) { for (let i = 0; i < res.data.data.records.length; i++) { if (res.data.data.records[i].tag != "RECOMMEND") { this.bannerItem.push(res.data.data.records[i]) } } console.log(this.bannerItem) } }, }) }, getHomeVideo() { this.selectedTagId = '0' uni.request({ url: BASE_URL + "/biz/series/page", methods: 'GET', header: { "programId": uni.getStorageSync("programId"), 'content-type': 'application/json; charset=utf-8;', "token": uni.getStorageSync("token"), }, data: { isPay: 'YES' }, success: (res) => { if (res.data.code == 200) { this.videoItem = res.data.data } }, fail: (e) => { console.log("错误:" + e) } }) }, // getHomeVideo() { // request.getHomeVideo({ // current: this.page, // size: 20, // }) // .then(res => { // this.videoItem = res.data.records // this.sortNewItem = this.videoItem // }) // }, bannerClik(item) { switch (item.tag) { case "VIDEO": // for (let i = 0; i < this.historyList.length; i++) { // if (this.historyList[i].seriesId == item.url) { // item.number = this.historyList[i].videoName // break // } // } const vip = uni.getStorageSync("userInfo").isVip const currentseries = { id: item.url, mediaId: item.mediaId, need: item.need, name: item.seriesName, start: item.start, totalVideo: item.totalVideo } // 注释掉与 PlayerManager 相关的代码 // if (vip != null && vip == "YES") { // PlayerManager.navigateToPlayer(item.mediaId, item.start - 1, item.totalVideo, currentseries) // } else if (item.isPay == "NO") { // PlayerManager.navigateToPlayer(item.mediaId, item.totalVideo, item.totalVideo, currentseries) // } else { // uni.request({ // url: BASE_URL + "/biz/order/getExpendByUser", // method: 'POST', // header: { // token: uni.getStorageSync("token") // }, // data: { // seriesName: currentseries.name, // userId: uni.getStorageSync("userInfo").id, // seriesId: currentseries.id // }, // success: (res) => { // const len = res.data.data.length // if (len > 0) { // uni.setStorageSync("haveVideo", res.data.data) // } // PlayerManager.navigateToPlayer(currentseries.mediaId, currentseries.start -1, 0, currentseries, len) // } // }) // } break case "URL": const webUrl = item.url uni.navigateTo({ url: "/packagesVideo/webView/webView?url=" + webUrl + "&title=" + item.title }) break; } }, getIndex() { let interstitialAd = null if (wx.createInterstitialAd) { interstitialAd = wx.createInterstitialAd({ adUnitId: 'adunit-66eeb550ffb21da4' }) interstitialAd.onLoad(() => {}) interstitialAd.onError((err) => {}) interstitialAd.onClose(() => {}) } if (interstitialAd) { interstitialAd.show().catch((err) => {}) } }, getSortTag() { this.tagList = [] var that = this uni.request({ url: BASE_URL + "/biz/videotag/page", method: 'GET', data: { current: 1, size: 50 }, success(res) { if (res.data.code === 200) { that.tagList = res.data.data.records } } }) }, //热播TOP tableSort() { uni.navigateTo({ url: "/packagesVideo/videoSort/videoSort" }) }, //签到 tableSign() { let token = uni.getStorageSync("token"); if (token == "") { uni.navigateTo({ url: "/packagesUser/login/login" }) } else { uni.navigateTo({ url: "/packagesUser/sign/sign" }) } }, //视频列表 --- 视频播放 videoPlay(item) { let token = uni.getStorageSync("token"); if (token == "") { uni.navigateTo({ url: "/packagesUser/login/login", }) } else { // 注释掉与 PlayerManager 相关的代码 // const vip = uni.getStorageSync("userInfo").isVip // if (vip != null && vip == "YES") { // PlayerManager.navigateToPlayer(item.mediaId, item.start - 1, item.totalVideo, item) // } else if (item.isPay == "NO") { // PlayerManager.navigateToPlayer(item.mediaId, item.totalVideo, // item.totalVideo, item) // } else { // uni.request({ // url: BASE_URL + "/biz/order/getExpendByUser", // method: 'POST', // header: { // token: uni.getStorageSync("token") // }, // data: { // seriesName: item.name, // userId: uni.getStorageSync("userInfo").id, // seriesId: item.id // }, // success: (res) => { // const len = res.data.data.length // PlayerManager.navigateToPlayer(item.mediaId, item.start - 1, 0, item, len) // if (len > 0) { // uni.setStorageSync("haveVideo", res.data.data) // } // } // }) // } } }, queryDict() { uni.request({ url: BASE_URL + "/dev/dict/tree", method: "GET", header: { "programId": uni.getStorageSync("programId"), 'content-type': 'application/json; charset=utf-8;', }, success: (res) => { uni.setStorageSync("dict", res.data.data) } }) }, getSortList() { uni.request({ url: BASE_URL + "/biz/series/getRank", method: 'GET', header: { "programId": uni.getStorageSync("programId"), "token": uni.getStorageSync("token") }, data: { current:1, size: 3 }, success: (res) => { if (res.data.code == 200) { //this.sortHighItem = res.data.data if (res.data.data.records.length > 8) { this.hotVideoItem = res.data.data.records.slice(0, 8) } else { this.hotVideoItem = res.data.data.records } } } }) }, getHistory() { console.log(BASE_URL) uni.request({ url: BASE_URL + "/history/getByUser", method: 'GET', header: { "token": uni.getStorageSync("token") }, success: (res) => { if (res.data.code == 200) { this.historyList = [] if (res.data.data.length > 0) { this.historyList.push(res.data.data[0]) } } } }) }, // 推荐页数据 getRecommend() { var that = this uni.request({ url: BASE_URL + "/biz/seriesvideo/recommend", method: 'GET', header: { "token": uni.getStorageSync("token"), "programId": uni.getStorageSync("programId"), }, data: { current: that.page, size: 20, userId: uni.getStorageSync("userInfo").id }, success: (res) => { if (res.data.data.records.length > 0) { for (let i = 0; i < res.data.data.records.length; i++) { res.data.data.records[i].isplay = true res.data.data.records[i].state = "pause" res.data.data.records[i].playIng = false } uni.setStorageSync("recommendList", res.data.data.records) console.log("获取推荐数据") console.log(uni.getStorageSync("recommendList")) } }, fail(e) { console.log("错误:" + e) } }) }, getSeriesByLink(param) { var that = this uni.request({ url: BASE_URL + "/biz/link/queryByLink", method: 'GET', header: { "token": uni.getStorageSync("token"), "programId": uni.getStorageSync("programId"), }, data: { link: param }, success: (res) => { this.seriesId = res.data.data.seriesId this.mediaId = res.data.data.mediaId this.seriesName = res.data.data.seriesName } }) }, getSortVideo(param) { this.selectedTagId = param.id uni.request({ url: BASE_URL + "/biz/videotag/getSeriesListById", method: 'GET', header: { "token": uni.getStorageSync("token") }, data: { id: param.id }, success: (res) => { if (res.data.code) { this.sortItem = res.data.data } } }) }, toPlay() { uni.request({ url: BASE_URL + '/biz/series/detail', method: 'GET', data: { id: this.historyList[0].seriesId }, success: (res) => { // 注释掉与 PlayerManager 相关的代码 // const vip = uni.getStorageSync("userInfo").isVip // if (vip != null && vip == "YES") { // PlayerManager.navigateToPlayer(res.data.data.mediaId, res.data.data.start - 1, // res.data.data.totalVideo, res.data.data) // } else if (res.data.data.isPay == "NO") { // PlayerManager.navigateToPlayer(res.data.data.mediaId, res.data.data.totalVideo, // res.data.data.totalVideo, res.data.data) // } else { // const seriesdetail = res.data.data // uni.request({ // url: BASE_URL + "/biz/order/getExpendByUser", // method: 'POST', // header: { // token: uni.getStorageSync("token") // }, // data: { // seriesName: seriesdetail.name, // userId: uni.getStorageSync("userInfo").id, // seriesId: seriesdetail.id // }, // success: (res) => { // const len = res.data.data.length // PlayerManager.navigateToPlayer(seriesdetail.mediaId, // seriesdetail.start - 1, 0, seriesdetail, len) // if (len > 0) { // uni.setStorageSync("haveVideo", res.data.data) // } // } // }) // } } }) } } } </script> <style lang="scss"> page { background-color: #f6f6f6; // banner .view_banner { height: 100%; align-self: center; transform-style: preserve-3d; .swiper_banner { text-align: center; border-radius: 25px; width: 96%; height: 90%; margin-left: 2%; margin-right: 2%; image { width: 100%; height: 100%; border-radius: 25px; // transform: scale(0.8); } } } .swiper_banner-active image { transform: scale(0.2); } .container { background: linear-gradient(to bottom, #87a5fe, #f6f6f6); height: 250px; } .gradient-background { background: linear-gradient(to bottom, #b6d6ff, #f6f6f6); border-radius: 16px; } // banner下功能按钮 .function-btn { margin-top: 20px; display: flex; flex-wrap: wrap; justify-content: space-between; .btn-history { width: 25%; box-sizing: border-box; text-align: center; padding: 10px; .btn-image { width: 30px; height: 30px; } .btn-text { color: black; font-size: 14px; text-align: center; } } } .text-container { background: linear-gradient(to right, #3d8aff, #67a4ff); } .view-desc { color: #217aff; margin-left: 20px; margin-top: 10px; display: flex; align-items: center; width: 50%; font-size: 20px; font-weight: 700; image { width: 22px; height: 22px; margin-right: 5px; } } .video-number { border-top-left-radius: 5px; border-bottom-right-radius: 5px; padding: 2px 10px; font-size: 10px; color: white; background-image: linear-gradient(90deg, #ff4eb5 0%, #ffa065 100%); } .selected-text text { font-size: 16px; color: #3d8aff; } // 优选好剧 .container-video { width: 100%; min-height: 550px; margin-left: 1%; margin-right: 1%; text-align: left; .video-list { width: 46%; height: 350px; background: white; border-radius: 8px; text-align: left; .video-item { display: grid; margin: -5%; image { width: 100%; height: 280px; } text { margin-left: 3%; font-size: 16px; color: black; text-overflow: ellipsis; width: 100%; overflow: hidden; word-break: break-all; display: -webkit-box; overflow: hidden; word-wrap: break-word; white-space: normal !important; -webkit-line-clamp: 1; -webkit-box-orient: vertical; text-align: left; margin-top: 2%; } } } } //热播TOP .scrollContainer { height: auto; margin-top: 20px; white-space: nowrap; padding-bottom: 10px; .scrollitem { width: 80px; background-color: rgba(0, 0, 0, 0.3); border-radius: 10px; display: inline-block; margin-left: 15rpx; height: auto; padding-bottom: 10px; color: white; text-align: center; image { width: 80px; height: 125px; margin-right: 10px; border-radius: 5px; } .sort-content { .video-name { font-size: 13px; margin-top: 5px; display: -webkit-box; overflow: hidden; text-overflow: ellipsis; word-wrap: break-word; white-space: normal !important; -webkit-line-clamp: 1; -webkit-box-orient: vertical; } .video-upload { font-size: 10px; color: lightslategray; } } .sort-txt { .video-ji { font-size: 10px; margin-top: 5px; color: #33cccc; } } } } .end-style { overflow: hidden; position: fixed; width: 100%; bottom: 0; } .close-button { position: absolute; top: 10px; right: 10px; font-size: 24px; color: white; cursor: pointer; } .collapsible-view { width: 96%; height: 100px; margin: 2%; background-color: rgba(0, 0, 0, 0.6); border-radius: 5px; transition: transform 0.3s ease; transform-origin: left; color: white; display: flex; } } </style> 学习这段代码
06-05
# 加载必要的库 library(cowplot) library(ggplot2) library(dplyr) library(tidyr) # 读取数据 df <- read.csv('rscu_all.csv', header = F) # 定义颜色 base_colors <- c('#8ECFC9','#FFBE7A','#FA7F6F','#82B0D2','#BEB8DC','#E7DAD2') # 数据预处理:按氨基酸(V2)分组,转长数据区分物种 df_processed <- df %>% # 按氨基酸(V2)分组(同一氨基酸的密码子堆积) group_by(V2) %>% # 按物种1的RSCU(V3)降序排序,确保两物种堆积顺序一致 arrange(desc(V3), .by_group = TRUE) %>% mutate(sort_order = row_number()) %>% # 密码子索引(控制堆积顺序) ungroup() %>% # 宽数据转长数据:将V3(物种1)和V4(物种2)转为“物种-值”对 pivot_longer( cols = c(V3, V4), # 要转换的列(两个物种的RSCU值) names_to = "Species", # 新列:物种标识(V3/V4) values_to = "RSCU" # 新列:RSCU数值 ) %>% # 将V3/V4转换为物种名称(Species1/Species2) mutate(Species = ifelse(Species == "V3", "Species1", "Species2")) %>% # 计算堆积块的中点位(用于标签居中) group_by(V2, Species) %>% arrange(sort_order, .by_group = TRUE) %>% # 强制按排序位累积 mutate( cumsum_RSCU = cumsum(RSCU), # 堆积高度累积值(顶部位) mid_y = cumsum_RSCU - RSCU/2 # 堆积块中点(标签y坐标) ) %>% ungroup() df_processed %>% filter(V2 == "Ala", Species == "Species1") %>% select(V1, V5) # 若V5有4个不同值(如4.5、5、5.5、6),则会拆分group # 绘制双物种并列堆积柱状图 p_dual_stack <- ggplot(df_processed, aes(x = V2, y = RSCU,group=interaction(Species, V2),fill = as.character(V5), color=Species))+ # 堆积柱状图:按密码子(V1)填充,双物种并列 geom_col( position = position_dodge( width = 0.7, # 物种间并列间距(大于柱子宽度,避免重叠) preserve = "single" ), alpha = 0.8, width = 0.6, # 单个堆积柱的宽度 size = 0.5 ) + # 颜色配 scale_fill_manual(values = base_colors) + scale_color_manual( values = c("Species1" = "black", "Species2" = "black"), # V3=黑,V4=深红 name = "none" # 图例名称(可选,说明框线色含义) )+ # y轴设 scale_y_continuous( breaks = seq(0, ceiling(max(df_processed$cumsum_RSCU)), 1), limits = c(0, max(df_processed$cumsum_RSCU) + 0.5), # 基于累积值设上限 expand = c(0, 0), name = "RSCU Value" ) + # 主题优化 theme_bw() + theme( axis.text.x = element_text(angle = 0, hjust = 0.5, size = 10), # 氨基酸标签旋转 axis.title.x = element_blank(), # x轴为氨基酸(V2),无需额外标题 legend.position = "none", # 若密码子太多,可隐藏图例 panel.grid = element_blank() ) + labs(fill = "Codon") # 图例标题(若显示图例) # 绘制文字标签图 p_labels <- ggplot(data = df_processed, mapping = aes(x = V2, y = V5, fill = as.character(V5))) + geom_label(mapping = aes(label = V1), size = 4) + theme_minimal() + ylim(3.4, 6.1) + theme(legend.position = 'none', axis.title = element_blank(), axis.text = element_blank(), panel.grid = element_blank()) + scale_fill_manual(values = base_colors) # 组合图形,将p_combined和p_labels上下组合 plot_combined <- plot_grid(p_dual_stack, p_labels, ncol = 1, align = 'v', axis = 'tblr', rel_heights = c(1, 0.3)) print(plot_combined) # 验证堆积效果:查看Ala的堆积高度是否与累积值一致 test_stack <- df_processed %>% filter(V2 == "Ala") %>% select(V2, V1, Species, RSCU, cumsum_RSCU) %>% arrange(Species, desc(cumsum_RSCU)) # 按累积值降序,看最大累积是否=4 print(test_stack) 检查一下上述代码,分析为什么会出现图中堆积块高度和y轴不一致的情况
10-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值